pax_global_header00006660000000000000000000000064146703577650014536gustar00rootroot0000000000000052 comment=0badded46d2cabdc94d1da9a94e883d086bd3c04 powerman-2.4.4/000077500000000000000000000000001467035776500133755ustar00rootroot00000000000000powerman-2.4.4/.github/000077500000000000000000000000001467035776500147355ustar00rootroot00000000000000powerman-2.4.4/.github/workflows/000077500000000000000000000000001467035776500167725ustar00rootroot00000000000000powerman-2.4.4/.github/workflows/main.yml000066400000000000000000000024561467035776500204500ustar00rootroot00000000000000name: ci on: [ pull_request, push ] jobs: build: runs-on: ${{matrix.os}} strategy: matrix: cc: [gcc, clang] os: [ubuntu-latest, ubuntu-20.04] steps: - uses: actions/checkout@v2 - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y \ libsnmp-dev \ libwrap0-dev \ libcurl4-gnutls-dev \ libgenders0-dev \ libjansson-dev \ automake \ autoconf \ pkg-config \ ${{matrix.cc}} - name: Display configuration run: | echo "C compiler:" ${CC} --version env: CC: ${{matrix.cc}} - name: autogen run: ./autogen.sh - name: configure run: | ./configure \ --with-genders \ --with-snmppower \ --with-httppower \ --with-redfishpower \ --with-tcp-wrappers - name: make run: make - name: make check run: make check - name: make distcheck run: DISTCHECK_CONFIGURE_FLAGS=--with-redfishpower make distcheck spelling: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 - name: Check Spelling uses: crate-ci/typos@e477391cc0243daaeeb154a7bfa67cb7d6fc5831 # v1.16.8 powerman-2.4.4/.gitignore000066400000000000000000000011371467035776500153670ustar00rootroot00000000000000# http://www.gnu.org/software/automake Makefile.in # http://www.gnu.org/software/autoconf autom4te.cache compile configure aclocal.m4 stamp-h1 aclocal.m4 config.guess config.sub depcomp install-sh ltmain.sh missing ylwrap config.log config.status config.h config.h.in libtool .deps/ .libs/ # Object files *.o *.ko *.obj *.elf # Libraries *.lib *.a *.la *.lo # Shared objects (inc. Windows DLLs) *.dll *.so *.so.* *.dylib # Executables *.exe *.out *.app *.i*86 *.x86_64 *.hex # autoconf-preprocessed Makefile *.1 *.3 *.5 *.8 *.spec *.pc *.diff *.swp *.tar.gz *.trs *.log .dirstsamp test_*.t debbuild/* powerman-2.4.4/.mergify.yml000066400000000000000000000013211467035776500156350ustar00rootroot00000000000000queue_rules: - name: default conditions: - base=master - label="merge-when-passing" - label!="work-in-progress" - "approved-reviews-by=@chaos/powerman" - "#approved-reviews-by>0" - "#changes-requested-reviews-by=0" - -title~=^\[*[Ww][Ii][Pp] pull_request_rules: - name: rebase and merge when passing all checks conditions: - base=master - label="merge-when-passing" - label!="work-in-progress" - -title~=^\[*[Ww][Ii][Pp] - "approved-reviews-by=@chaos/powerman" - "#approved-reviews-by>0" - "#changes-requested-reviews-by=0" actions: queue: name: default method: merge update_method: rebase powerman-2.4.4/.typos.toml000066400000000000000000000005751467035776500155350ustar00rootroot00000000000000# do not check code copied into the project # do not check sha code, lots of hashing false positives # do not check testing data [files] extend-exclude = [ "config/*", "src/liblsd/*", "src/libczmq/*", "t/sharness.sh", "t/t0000-sharness.t", "t/aggregate-results.sh", ] [default.extend-words] # commonly used names/variables that aren't typos SER = "SER" admn = "admn" powerman-2.4.4/COPYING000066400000000000000000000431311467035776500144320ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library General Public License instead of this License. powerman-2.4.4/DISCLAIMER000066400000000000000000000045701467035776500147420ustar00rootroot00000000000000Copyright (C) 2001 The Regents of the University of California. Produced at Lawrence Livermore National Laboratory. Written by Andrew Uselton (uselton2@llnl.gov>. UCRL-CODE-2002-008. This file is part of PowerMan, a remote power management program. For details, see . PowerMan 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. PowerMan is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with PowerMan; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. This work was produced at the University of California, Lawrence Livermore National Laboratory (UC LLNL) under contract no. W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy (DOE) and The Regents of the University of California (University) for the operation of UC LLNL. The rights of the Federal Government are reserved under Contract 48 subject to the restrictions agreed upon by the DOE and University as allowed under DOE Acquisition Letter 97-1. DISCLAIMER This work was prepared as an account of work sponsored by an agency of the United States Government. Neither the United States Government nor the University of California nor any of their employees, makes any warranty, express or implied, or assumes any liability or responsibility for the accuracy, completeness, or usefulness of any information, apparatus, product, or process disclosed, or represents that its use would not infringe privately-owned rights. Reference herein to any specific commercial products, process, or service by trade name, trademark, manufacturer or otherwise does not necessarily constitute or imply its endorsement, recommendation, or favoring by the United States Government or the University of California. The views and opinions of authors expressed herein do not necessarily state or reflect those of the United States Government or the University of California, and shall not be used for advertising or product endorsement purposes. powerman-2.4.4/Makefile.am000066400000000000000000000011361467035776500154320ustar00rootroot00000000000000SUBDIRS = \ etc \ man \ heartbeat \ src \ t # Create run dir for powerman. Chown will fail if non root - ignore it. install-data-local: -$(top_srcdir)/config/install-sh -m 755 -d \ $(DESTDIR)$(localstatedir)/run -$(top_srcdir)/config/install-sh -o $(RUN_AS_USER) -m 755 -d \ $(DESTDIR)$(localstatedir)/run/powerman EXTRA_DIST = \ DISCLAIMER \ NEWS.md \ examples/powerman_el72.spec \ config/tap-driver.sh \ scripts/debbuild.sh \ scripts/install-deps-deb.sh export DEB_BUILD_OPTIONS ?= nocheck terse deb: debian scripts/debbuild.sh +@$(top_srcdir)/scripts/debbuild.sh $(abs_top_srcdir) powerman-2.4.4/NEWS.md000066400000000000000000000411531467035776500144770ustar00rootroot00000000000000powerman-2.4.4 - 11 Sep 2024 ---------------------------- Fix segfault affecting systems with power control hierarchy. ## Fixes * powerman: fix segfault if unspecified host reports status * redfishpower: do not report errors on dependent hosts * Update hostlist library to fix potential array out of bounds error. powerman-2.4.3 - 11 Jul 2024 ---------------------------- Command lines can be very long on a big system. ## Fixes * powerman: increase maximum line length powerman-2.4.2 - 02 May 2024 ---------------------------- More tuning for the large Cray EX system, and a work-around for a libcurl bug on RHEL 8. ## New features * redfishpower: cache host resolution lookups (#190) * redfishpower: support new --resolve-hosts option (#188) * redfishpower: support message timeout config (#186) ## FIxes * redfishpower: increase default message timeout (#191) * redfishpower: output more detailed error messages (#183) powerman-2.4.1 - 12 Apr 2024 ---------------------------- This release represents a focused effort to support a large Cray EX system including adding support in redfishpower to handle the power hierarchy of Chassis/Blade/Node sensibly, and to better handle expected failure modes. Powerman now supports the ability for a device script to match error output and fail immediately. Prior to this release, the only way to get powerman to fail was to not provide expected successful output and run out the device timeout. ## New features * redfishpower: support auth setup on command line (#181) * set default Cray EX authentication (#179) * add device file for Cray EX w/ Rabbit (#177) * add redfishpower HPE Cray EX chassis device file (#173) * powerman: support error diagnostics with setresult (#172) * redfishpower: add more details on hierarchy errors (#174) * powerman: support new setresult directive (#168) * powerman: use singlet script if targeting one plug (#170) * redfishpower: support plug parents (#164) * redfishpower: support plug substitution (#159) * redfishpower: support setpath configuration (#158) * redfishpower: support setplugs configuration (#157) * redfishpower: refactor internals to use plugs (#160) * redfishpower: always do off/delay/on for power cycle (#149) * redfishpower: send http request after cmd active (#146) * powermand: don't daemonize and drop -f,--foreground option (#141) * libczmq: add containers from the CZMQ project (#124) ## Fixes * redfishpower: adapt status polling interval (#167) * redfishpower: fix memleaks and test under valgrind (#169) * powerman: when status and status_all are defined, use status_all only on full pluglist (#156) * redfishpower: add extra timeout debug information (#154) * redfishpower: adjust verbosity output (#151) * reduce log noise (#140) * don't allocate a pseudo-terminal for each coprocess (#135) * redfishpower: handle http 400 error (#132) ## Cleanup * drop antiquated memory protection magic (#136) * redfishpower: cleanup & refactoring (#134) ## CI/Test/build system * configure.ac: build helper executables by default (#180) * test a huge cray-ex configuration (#127) * redfishpower: reduce polling interval in test mode (#155) * redfishpower: add option to test host errors (#145) * redfishpower: support test mode (#143) * enable valgrind test with suppressions (#137) powerman-2.4.0 - 06 Feb 2024 ---------------------------- This release is the result of a concentrated cleanup and modernization effort. The minor version was incremented because some options have changed which could affect scripts that drive powerman. ## New features * systemd: run as Type=simple (#114) * redfishpower: output extra error info (#97) * systemd: allow group to be configured and set SHELL in env; add UBNT edge device (#96) * redfishpower: allow timeout to be set by device script (#72) ## Fixes * powermand: fix assertion failure on teardown (#118) * etc: fix logic error in redfishpower cray windom (#70) * redfishpower: check for post data (#66) ## Documentation * improve --device documentation and testing (#116) * Add license text to header files (#93) * Update license headers to SPDX license identifier (#92) ## Cleanup * redfishpower: remove --hostsfile option (#123) * redfishpower: minor cleanup (#117) * cull unused test options and update manual pages (#112) * clean up powerman client options (#113) * improve the powerman client's usage/help output, and minor source cleanup (#95) * reorganize project directories (#86) * drop trailing whitespace from configs, etc (#82) * Fix misleading-indentation error when running make on RHEL9 (#65) * systemd: avoid hardcoded paths and locate pid file under /run (#62) ## CI/Test/build system * testsuite: add valgrind coverage (#120) * testsuite: add clarification to sierra test script (#121) * convert remaining tests to sharness (#111) * convert more tests to sharness (#109) * convert old school power control box tests to sharness (#108) * convert still more tests to the sharness framework (#104) * convert more tests to use the sharness framework (#103) * convert several tests to use the sharness framework (#102) * testsuite: add sharness scripts (#98) * add test deb packaging and fix misc build problems (#91) * testsuite: use TAP for unit tests (#87) * mergify: fix approved-reviews-by typo (#90) * .mergify.yml: Add mergify support (#89) * build: modernize autoconf, fix bison/flex detection (#84) * test: fix redfishpower tests (#71) * testsuite: fix parallel make failure (#64) * require warning-free compilation (#61) powerman-2.3.27 - 14 Dec 2021 ----------------------------- * Add redfish support for Cray r272z30, Cray windom, and Supermicro H12DSG-O-CPU (#55, #47) * CI: Enable github workflow (#59, #58, #57, #56) * Misc fixes (#54, #52, #50, #46) powerman-2.3.26 - 18 Feb 2020 ----------------------------- * Log power state changes to syslog (Olaf Faaland, PR #37) * Fix default systemd unit file path for 'make distcheck' powerman-2.3.25 - 28 Jan 2019 ----------------------------- * Add etc/rancid-cisco-poe.dev (Daniel Rich, PR #28) * Add etc/openbmc.dev (Albert Chu, PR #33) * Add etc/kvm.dev & etc/kvm-ssh.dev (tisbeok, PR #8) * Fix misinterpretation of error strings in ipmipower.dev. powerman-2.3.24 - 23 Oct 2015 ----------------------------- * Don't package /var/run/powerman; let systemd manage it [TOSS-2987] * Cleanup: drop trailing whitespace powerman-2.3.23 - 08 Jun 2015 ----------------------------- * Build: silence CC lines, fix AC_LANG_CONFTEST warnings, fix $(EXEEXT) warnings. * Build: install System V init scripts if --with-systemdsystemunitdir is not configured and include both in EXTRA_DIST. * Build: re-enable 'make check' unit tests. * Build: fix some 'make distcheck' issues, but until unit tests are fixed to find *.exp and *.conf files in $(srcdir), this will still fail. * RPM: configure genders, httppower, snmppower, and tcp-wrappers unconditionally; update URL. powerman-2.3.22 - 01 Jun 2015 ----------------------------- * Assorted build system fixes to allow 'make distcheck' and Koji builds on RHEL 7 to work. * Note: unit tests temporarily disabled pending rework. [This release was not distributed as it was incomplete for RHEL 7/Koji] powerman-2.3.21 - 29 May 2015 ----------------------------- * Added systemd unit file (bacaldwell, gc issue #42) SystemVinit script support is dropped. * Build against -lnetsnmp not -lsnmp (TOSS-2815) * Add raritan-px5523.dev (Daryl Granau, TOSS-2486) powerman-2.3.20 - 26 Aug 2014 ----------------------------- * add dist tag to release (TOSS-2667) * Minor automake updates powerman-2.3.19 - 25 Aug 2014 ----------------------------- * Added apc8941.dev (TOSS-2658, Tim Randles) powerman-2.3.18 - 21 Aug 2014 ----------------------------- * Stop tracking autotools products * Add README.md for github move powerman-2.3.17 - 27 Mar 2013 ----------------------------- * Fix powerman-stonith script to handle aliased plugs and add regression testing for it (TOSS-1962) powerman-2.3.16 - 04 Oct 2012 ----------------------------- * Fix duplicate node name (issue 35) Pulled in another hostlist fix (Mark Grondona) * Fix powerman stonith OFF should verify plug state (chaos bz 1439) powerman-2.3.15 - 05 Sep 2012 ----------------------------- * Added ipmipower-serial.dev [Al Chu] powerman-2.3.14 - 10 Aug 2012 ----------------------------- * Fix issue 34: duplicate node name in configuration file Updated hostlist code to the latest which fixes this issue. powerman-2.3.13 - 20 Jun 2012 ----------------------------- * Updated appro-gb2.dev per Appro * Add support for Baytech RPC22 (Olof Johansson) powerman-2.3.12 - 13 Jan 2012 ----------------------------- * Add support for Raritan px4316 (chaos bz 1276) * Add support for DLI web power switches III and IV [Gaylord Holder] * Add --single-cmd option to plmpower (issue 7) [Ira Weiny] * Minor documentation updates powerman-2.3.11 - 01 Sep 2011 ----------------------------- * Update appro-gb2.dev (chaos bug 1218) * Fix BuildRequires for tcp_wrappers-devel to work on el6/ch5. Packagers: now you must add --with-tcp-wrappers on configure line to enable this feature (before it was enabled if libs were present) * Re-autogen to pull in (new?) bison build dependency on el6/ch5. * Fix --with-feature options to fail if prereqs are missing, not just silently disable the feature. * Fix line number accounting during parse error reporting (issue 3) powerman-2.3.10 - 19 Aug 2011 ----------------------------- * Updated appro-greenblade.dev (chaos bug 1218) * Added appro-gb2.dev (chaos bug 1218) * Added sentry_cdu.dev (chaos bug 1218) * Added baytech-rpc18d-nc (issue 5) powerman-2.3.9 - 25 Feb 2011 ---------------------------- * Add MIB support to snmppower. * Add eaton-epdu-blue-switched.dev [Paul Anderson]. powerman-2.3.8 - 24 Feb 2011 ---------------------------- * Add support for SNMP power controllers via 'snmppower' helper. * Add SNMP dev files for 8-port APC, 8-port Baytech, and 20 port Eaton Revelation PDU. powerman-2.3.7 - 04 Nov 2010 ---------------------------- * Add support for APC 7900 revision 3 firmware [Py Watson] * Internal automake cleanup. powerman-2.3.6 - 12 Aug 2010 ---------------------------- * Convert several internal buffers from static to dynamic to address overflow in query output [chaos bugzilla 1009] * Add support for Appro Greenblade [Trent D'Hooge]. * Add support for APC 7920 [Manfred Gruber]. * Add Support for ranged beacon on/off device scripts, and beacon support for ipmipower [Al Chu]. powerman-2.3.5 - 17 Apr 2009 ---------------------------- * Deprecated undocumented powerman.conf port directive. * Added powerman.conf listen directive to configure which interfaces and ports the server listens on. Make the default localhost:10101. * Add support for HP integrated power control devices [Bjorn Helgaas] * Add support for Sun LOM. * Misc. documentation improvements * Add heartbeat STONITH plugin. powerman-2.3.4 - 09 Feb 2009 ---------------------------- * Fix powerman-controlling-powerman config so that status command is fast for large configs again. * Fix "bashfun" device script and add regression test. * Various changes coming from Debian audit [Arnaud Quette]. powerman-2.3.1 - 01 Dec 2008 ---------------------------- * Initial powerman client API. * Run the powerman daemon (and all coprocesses) as 'daemon' by default instead of root. To override, set USER=root or other user in /etc/sysconfig/powerman. * New man pages for httppower, plmpower, libpowerman, vpcd. * Include vpcd in the dist. * Various changes coming from Debian audit [Arnaud Quette]. powerman-2.3 - 12 Nov 2008 -------------------------- * Make init script work on Solaris. * IPv6 support. * Include example powerman.conf file (/etc/powerman/powerman.conf.example) * Added support for Cyclades PM20, PM42. powerman-2.2 - 27 Aug 2008 -------------------------- * Send a SIGINT to coprocesses rather than just closing file descriptors during powermand shutdown. This is required to terminate an ssh client running in coprocess mode. * Make it possible to only define the _ranged version of scripts. Scripts are selected using the following precedence: _all, _ranged, singlet. * Drop "soft power status" support. This allowed iceboxes to detect whether a node was powered up or not, independently of plug state. * [ipmipower] Drop _all and singlet version of scripts. * [ilom] Revised Sun Integrated Lights Out Management support to work over ssh and serial. Dropped shared console/serial "ilom-inline" support. * [icebox3] Now supports both v3 and v4 Ice Box. Users of icebox4 should change their device types to icebox3 in powerman.conf. * [plmpower] Added support for controlling Insteon/X10 devices via SmartLabs PLM 2412S. * [hp3488] Added support for modular GPIB-based HP 3488A switch/control unit via gpib-utils project. * [ics8064] Added support for VXI-11-based ICS 8064 16-port relay unit via gpib-utils project. * [powerman] Improved efficiency of powerman-controlling-powerman configurations, when one powerman controls a subset of the plugs of another powerman through the use of _ranged scripts. * Enhanced integrated test suite. Note: tests all pass on AIX now. powerman-2.1 - 18 Jun 2008 -------------------------- * Client overhaul. * [apcpdu3] Fix intermittent query failures. * Fixed off by one bug in server that allowed some delays in dev scripts to take longer than programmed. * Use raw mode in pipe (|&) connections to avoid local tty echo. * Run server in /var/run/powerman rather than /etc/powerman. Create this directory if it doesn't exist. * Enhanced integrated test suite. Note: all tests do not currently pass on AIX. powerman-2.0 - 01 Jun 2008 -------------------------- * Autoconf/automake integration. * Integrated test suite. * Portability to Solaris, AIX, and OS/X. * Support for selecting power control targets using genders (-g option). * Cleanup and refactoring. powerman-1.0.32 - 24 Jan 2008 ----------------------------- * Support for new apc firmware (apcpdu3.dev) [Trent D'Hooge] * Added httppower utility for interfacing to power controllers that are exclusively web-based. * Support for Digital Loggers, Inc. power controllers. * Support for APPRO power controller. powerman-1.0.31 - 20 Oct 2007 ----------------------------- (Includes changes in 1.0.29 and 1.0.30) * Support SUN ILOM inline with serial console, i.e. device "ilom25" "ilom-inline" "/usr/bin/conman -Q -j ilc25 |&" * Handle config files with embedded carriage returns [Trent D'Hooge and Todd Heer]. * Ipmipower device script tuning [Al Chu]. * Minor build/packaging tweaks for building under mock, etc. powerman-1.0.28 - 07 May 2007 ----------------------------- * Increase "cycle" delays from 2s to 4s on all devices that implement cycle as an explicit on,delay,off. powerman-1.0.27 - 24 Apr 2007 ----------------------------- * Add heartbeat stonith module. * Fix bug in baytech-rpc28-nc device support that affected plugs > 10. powerman-1.0.26 - 21 Dec 2006 ----------------------------- * Support 8-port APC AP7900 and likely AP7901, AP7920, and AP7921. [Martin Petersen] * Work around a bug that causes baytech rpc3's to return some plugs as status "unknown" on login timeout/reconnect. * Add ranged power control support for faster power control w/ ipmipower. powerman-1.0.25 - 16 Aug 2006 ----------------------------- * Support newer baytech RPC-3 firmware. * Support icebox v4 [Jarod Wilson] powerman-1.0.24 - 30 May 2006 ----------------------------- * Telnet state machine now works with Digi terminal server in telnet mode and logs ignored telnet option requests. * Several powerman.conf examples are now included in the RPM doc area. * Handle expansion of suffixed host ranges, e.g. "[00-26]p" [Mark Grondona] * Fix minor memory leaks and unchecked function return values found by Coverity. * New powerman.dev(5) man page documenting device file syntax. * Support serial device baud rates up to 460800 baud if system does. * Minor tweaks to spec file for Fedora Extras [Ben Woodard]. * Fix for broken P0|P1 in Rackable Phantom 4.0 firmware (phantom4.dev). * Add support for IBM BladeCenter chassis (ibmbladecenter.dev) [Robin Goldstone]. * Add support for ComputerBoards CB7050 (cb-7050.dev). * Add support for Cyclades PM10 (cyclades-pm10.dev) [Trent D'Hooge]. powerman-1.0.23 - 16 Feb 2006 ----------------------------- * Fix for compilation on Fedora Core 4 [Ben Woodard]. * Spec file changes for Fedora Extras submission [Ben Woodard]. powerman-1.0.22 - 12 Oct 2005 ----------------------------- * Bug fix for powerman -T dumps core on x86_64 [Thayne Harbaugh] * Add support for 24-port APC Switched Rack PDU (apcpdu.dev) [Makia Minnich]. powerman-2.4.4/README.md000066400000000000000000000021201467035776500146470ustar00rootroot00000000000000*powerman* is free UNIX/Linux software that controls (remotely and in parallel) switched power distribution units. It was designed for remote power control of Linux systems in a data center or cluster environment, but has been used in other environments such as embedded management appliances, home automation, and high availability service management. *powerman* can be extended to support new devices using an expect-like scripting language. It communicates with devices natively using telnet, raw socket, and serial protocols. It also can drive virtual power control devices via a coprocess interface. The coprocess mechanism has been used to extend *powerman* to communicate with devices using other protocols such as SNMP, IPMI, Insteon, and Redfish. *powerman* can control equipment connected using any combination of the above methods and provide unified naming for the equipment and parallel execution of control actions. #### Origin and license Originally written by Andrew Uselton in 2002 for early Linux clusters at LLNL. SPDX-License-Identifier: GPL-2.0-or-later UCRL-CODE-2002-008 powerman-2.4.4/autogen.sh000077500000000000000000000006161467035776500154010ustar00rootroot00000000000000#!/bin/sh # # Run an extra libtoolize before autoreconf to ensure that # libtool macros can be found if libtool is in PATH, but its # macros are not in default aclocal search path. # echo "Running libtoolize --automake --copy ... " libtoolize --automake --copy || exit echo "Running autoreconf --force --verbose --install" autoreconf --force --verbose --install || exit echo "Now run ./configure." powerman-2.4.4/config/000077500000000000000000000000001467035776500146425ustar00rootroot00000000000000powerman-2.4.4/config/ac_genders.m4000066400000000000000000000014261467035776500172010ustar00rootroot00000000000000# # Add --with-genders configure option (no by default). # If yes, not finding header file or lib is fatal. # Define WITH_GENDERS=1, HAVE_GENDERS_H=1, and HAVE_LIBGENDERS=1 in config.h. # Substitute LIBGENDERS with -lgenders in Makefiles. # AC_DEFUN([AC_GENDERS], [ AC_ARG_WITH([genders], AS_HELP_STRING([--with-genders], [Build genders support for client])) AS_IF([test "x$with_genders" = "xyes"], [ AC_CHECK_HEADERS([genders.h]) X_AC_CHECK_COND_LIB([genders], [genders_handle_create]) AC_DEFINE(WITH_GENDERS, 1, [Define if building genders support for client]) ]) AS_IF([test "x$with_genders" = "xyes" && test "x$ac_cv_header_genders_h" = "xno" -o "x$ac_cv_lib_genders_genders_handle_create" = "xno"], [ AC_MSG_ERROR([could not find genders library]) ]) ]) powerman-2.4.4/config/ac_httppower.m4000066400000000000000000000015151467035776500176050ustar00rootroot00000000000000# # Add --without-httppower configure option (build by default). # If yes, not finding curl header file or lib is fatal. # Define HAVE_CURL_CURL_H=1, and HAVE_LIBCURL=1 in config.h. # Substitute LIBCURL with -lcurl and define WITH_HTTPPOWER=1 in Makefiles. # # AC_DEFUN([AC_HTTPPOWER], [ AC_ARG_WITH([httppower], AS_HELP_STRING([--without-httppower], [Do not build httppower executable]), [], [with_httppower=yes]) AS_IF([test "x$with_httppower" = "xyes"], [ AC_CHECK_HEADERS([curl/curl.h]) X_AC_CHECK_COND_LIB([curl], [curl_easy_setopt]) ]) AS_IF([test "x$with_httppower" = "xyes" && test "x$ac_cv_header_curl_curl_h" = "xno" -o "x$ac_cv_lib_curl_curl_easy_setopt" = "xno"], [ AC_MSG_ERROR([could not find curl library for httppower]) ]) AM_CONDITIONAL(WITH_HTTPPOWER, [test "x$with_httppower" = "xyes"]) ]) powerman-2.4.4/config/ac_pkgconfig.m4000066400000000000000000000013761467035776500175250ustar00rootroot00000000000000# Thanks to Arnaud Quette for this bit of m4 AC_DEFUN([AC_PKGCONFIG], [ pkgconfigdir='${libdir}/pkgconfig' 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 ], ) if test -n "${pkgconfigdir}"; then AC_MSG_RESULT(${pkgconfigdir}) else AC_MSG_RESULT(no) fi AM_CONDITIONAL(WITH_PKG_CONFIG, test -n "${pkgconfigdir}") AC_SUBST(pkgconfigdir) ]) powerman-2.4.4/config/ac_redfishpower.m4000066400000000000000000000021151467035776500202470ustar00rootroot00000000000000# # Add --without-redfishpower configure option (build by default). # If yes, not finding curl or jansson is fatal. # AC_DEFUN([AC_REDFISHPOWER], [ AC_ARG_WITH([redfishpower], AS_HELP_STRING([--without-redfishpower], [Do not build redfishpower executable]), [], [with_redfishpower=yes]) AS_IF([test "x$with_redfishpower" = "xyes"], [ AC_CHECK_HEADERS([curl/curl.h]) X_AC_CHECK_COND_LIB([curl], [curl_multi_perform]) AC_CHECK_HEADERS([jansson.h]) X_AC_CHECK_COND_LIB([jansson], [json_object]) ]) AS_IF([test "x$with_redfishpower" = "xyes" \ && test "x$ac_cv_header_curl_curl_h" = "xno" \ -o "x$ac_cv_lib_curl_curl_multi_perform" = "xno"], [ AC_MSG_ERROR([could not find curl library for redfishpower]) ]) AS_IF([test "x$with_redfishpower" = "xyes" \ && test "x$ac_cv_header_jansson_h" = "xno" \ -o "x$ac_cv_lib_curl_json_object_set" = "xno"], [ AC_MSG_ERROR([could not find jansson library for redfishpower]) ]) AM_CONDITIONAL(WITH_REDFISHPOWER, [test "x$with_redfishpower" = "xyes"]) ]) powerman-2.4.4/config/ac_runas.m4000066400000000000000000000020131467035776500166730ustar00rootroot00000000000000AC_DEFUN([AC_RUNAS], [ RUN_AS_USER="daemon" RUN_AS_GROUP="daemon" AC_MSG_CHECKING(user to run as) AC_ARG_WITH(user, AS_HELP_STRING([--with-user=username], [user for powerman daemon (daemon)]), [ case "${withval}" in yes|no) ;; *) RUN_AS_USER="${withval}" ;; esac], ) AC_DEFINE_UNQUOTED(RUN_AS_USER, "${RUN_AS_USER}", [Powerman daemon user]) AC_MSG_RESULT(${RUN_AS_USER}) AC_SUBST(RUN_AS_USER) AC_MSG_CHECKING(group to run as) AC_ARG_WITH(group, AS_HELP_STRING([--with-group=groupname], [group for powerman daemon (daemon)]), [ case "${withval}" in yes|no) ;; *) RUN_AS_GROUP="${withval}" ;; esac], ) AC_DEFINE_UNQUOTED(RUN_AS_GROUP, "${RUN_AS_GROUP}", [Powerman daemon group]) AC_MSG_RESULT(${RUN_AS_GROUP}) AC_SUBST(RUN_AS_GROUP) ]) powerman-2.4.4/config/ac_snmppower.m4000066400000000000000000000015601467035776500176030ustar00rootroot00000000000000# # Add --without-snmppower configure option (build by default). # If yes, not finding netsnmp header file or lib is fatal. # Define HAVE_NET_SNMP_NET_SNMP_CONFIG_H=1 and HAVE_LIBSNMP=1 in config.h. # Substitute LIBSNMP with -lsnmp and define WITH_SNMPPOWER=1 in Makefiles. # AC_DEFUN([AC_SNMPPOWER], [ AC_ARG_WITH([snmppower], AS_HELP_STRING([--without-snmppower], [Do not build snmppower executable]), [], [with_snmppower=yes]) AS_IF([test "x$with_snmppower" = "xyes"], [ AC_CHECK_HEADERS([net-snmp/net-snmp-config.h]) X_AC_CHECK_COND_LIB([netsnmp], [init_snmp]) ]) AS_IF([test "x$with_snmppower" = "xyes" && test "x$ac_cv_header_net_snmp_net_snmp_config_h" = "xno" -o "x$ac_cv_lib_snmp_init_snmp" = "xno"], [ AC_MSG_ERROR([could not find snmp library for snmppower]) ]) AM_CONDITIONAL(WITH_SNMPPOWER, [test "x$with_snmppower" = "xyes"]) ]) powerman-2.4.4/config/ac_wrap.m4000066400000000000000000000014161467035776500165220ustar00rootroot00000000000000# # Add --with-tcp-wrappers configure option (no by default). # If yes, not finding tcpd.h header file or libwrap is fatal. # Define HAVE_TCP_WRAPPERS=1, HAVE_TCP_H=1, and HAVE_LIBWRAP=1 in config.h. # Substitute LIBWRAP with -lwrap in Makefiles. # AC_DEFUN([AC_WRAP], [ AC_ARG_WITH([tcp-wrappers], AS_HELP_STRING([--with-tcp-wrappers], [Build with tcp wrappers support])) AS_IF([test "x$with_tcp_wrappers" = "xyes"], [ AC_CHECK_HEADERS([tcpd.h]) X_AC_CHECK_COND_LIB([wrap], [hosts_ctl]) AC_DEFINE(HAVE_TCP_WRAPPERS, 1, [Define if building tcp wrappers support]) ]) AS_IF([test "x$with_tcp_wrappers" = "xyes" && test "x$ac_cv_header_tcpd_h" = "xno" -o "x$ac_cv_lib_wrap_hosts_ctl" = "xno"], [ AC_MSG_ERROR([could not find tcp wrappers library]) ]) ]) powerman-2.4.4/config/adl_recursive_eval.m4000066400000000000000000000013411467035776500207410ustar00rootroot00000000000000dnl dnl Unknown origin, but was presumably part of autoconf-archive at dnl some point in the past. dnl dnl adl_RECURSIVE_EVAL(VALUE, RESULT) dnl ================================= dnl Interpolate the VALUE in loop until it doesn't change, dnl and set the result to $RESULT. dnl WARNING: It's easy to get an infinite loop with some unsane input. AC_DEFUN([adl_RECURSIVE_EVAL], [_lcl_receval="$1" $2=`(test "x$prefix" = xNONE && prefix="$ac_default_prefix" test "x$exec_prefix" = xNONE && exec_prefix="${prefix}" _lcl_receval_old='' while test "[$]_lcl_receval_old" != "[$]_lcl_receval"; do _lcl_receval_old="[$]_lcl_receval" eval _lcl_receval="\"[$]_lcl_receval\"" done echo "[$]_lcl_receval")`]) powerman-2.4.4/config/ax_compiler_vendor.m4000066400000000000000000000070271467035776500207710ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html # =========================================================================== # # SYNOPSIS # # AX_COMPILER_VENDOR # # DESCRIPTION # # Determine the vendor of the C/C++ compiler, e.g., gnu, intel, ibm, sun, # hp, borland, comeau, dec, cray, kai, lcc, metrowerks, sgi, microsoft, # watcom, etc. The vendor is returned in the cache variable # $ax_cv_c_compiler_vendor for C and $ax_cv_cxx_compiler_vendor for C++. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2008 Matteo Frigo # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 16 AC_DEFUN([AX_COMPILER_VENDOR], [AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, dnl Please add if possible support to ax_compiler_version.m4 [# note: don't check for gcc first since some other compilers define __GNUC__ vendors="intel: __ICC,__ECC,__INTEL_COMPILER ibm: __xlc__,__xlC__,__IBMC__,__IBMCPP__ pathscale: __PATHCC__,__PATHSCALE__ clang: __clang__ cray: _CRAYC fujitsu: __FUJITSU gnu: __GNUC__ sun: __SUNPRO_C,__SUNPRO_CC hp: __HP_cc,__HP_aCC dec: __DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland: __BORLANDC__,__CODEGEARC__,__TURBOC__ comeau: __COMO__ kai: __KCC lcc: __LCC__ sgi: __sgi,sgi microsoft: _MSC_VER metrowerks: __MWERKS__ watcom: __WATCOMC__ portland: __PGI tcc: __TINYC__ unknown: UNKNOWN" for ventest in $vendors; do case $ventest in *:) vendor=$ventest; continue ;; *) vencpp="defined("`echo $ventest | sed 's/,/) || defined(/g'`")" ;; esac AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[ #if !($vencpp) thisisanerror; #endif ])], [break]) done ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=`echo $vendor | cut -d: -f1` ]) ]) powerman-2.4.4/config/systemd.m4000066400000000000000000000043451467035776500166020ustar00rootroot00000000000000dnl Probe for systemd libraries and installation paths. dnl dnl Provides the RRA_WITH_SYSTEMD_UNITDIR macro, which adds the dnl --with-systemdsystemunitdir configure flag, sets the systemdsystemunitdir dnl substitution variable, and provides the HAVE_SYSTEMD Automake conditional dnl to use to control whether to install unit files. dnl dnl Provides the RRA_LIB_SYSTEMD_DAEMON_OPTIONAL macro, which sets dnl SYSTEMD_CFLAGS and SYSTEMD_LIBS substitution variables if dnl libsystemd-daemon is available and defines HAVE_SD_NOTIFY. pkg-config dnl support for libsystemd-daemon is required for it to be detected. dnl dnl Depends on the Autoconf macros that come with pkg-config. dnl dnl The canonical version of this file is maintained in the rra-c-util dnl package, available at . dnl dnl Written by Russ Allbery dnl Copyright 2013, 2014 dnl The Board of Trustees of the Leland Stanford Junior University dnl dnl This file is free software; the authors give unlimited permission to copy dnl and/or distribute it, with or without modifications, as long as this dnl notice is preserved. dnl Determine the systemd system unit directory, along with a configure flag dnl to override, and sets @systemdsystemunitdir@. Provides the Automake dnl HAVE_SYSTEMD Automake conditional. AC_DEFUN([RRA_WITH_SYSTEMD_UNITDIR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) AS_IF([test x"$PKG_CONFIG" = x], [PKG_CONFIG=false]) AC_ARG_WITH([systemdsystemunitdir], [AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files])], [], [with_systemdsystemunitdir=\${prefix}$($PKG_CONFIG --variable=systemdsystemunitdir systemd)]) AS_IF([test x"$with_systemdsystemunitdir" != xno], [AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])]) AM_CONDITIONAL([HAVE_SYSTEMD], [test -n "$with_systemdsystemunitdir" -a x"$with_systemdsystemunitdir" != xno])]) dnl Check for libsystemd-daemon and define SYSTEMD_DAEMON_{CFLAGS,LIBS} if it dnl is available. AC_DEFUN([RRA_LIB_SYSTEMD_DAEMON_OPTIONAL], [PKG_CHECK_EXISTS([libsystemd-daemon], [PKG_CHECK_MODULES([SYSTEMD_DAEMON], [libsystemd-daemon]) AC_DEFINE([HAVE_SD_NOTIFY], 1, [Define if sd_notify is available.])])]) powerman-2.4.4/config/tap-driver.sh000077500000000000000000000503421467035776500172620ustar00rootroot00000000000000#! /bin/sh # Copyright (C) 2011-2013 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 # . scriptversion=2013-12-23.17; # UTC # Make unconditional expansion of undefined variables an error. This # helps a lot in preventing typo-related bugs. set -u me=tap-driver.sh fatal () { echo "$me: fatal: $*" >&2 exit 1 } usage_error () { echo "$me: $*" >&2 print_usage >&2 exit 2 } print_usage () { cat < # trap : 1 3 2 13 15 if test $merge -gt 0; then exec 2>&1 else exec 2>&3 fi if test -n "${FLUX_TEST_TIMEOUT:-}" ; then if test -z "${FLUX_SOURCE_DIR:-}"; then if test -n "${top_srcdir:-}" ; then FLUX_SOURCE_DIR="$top_srcdir" else SCRIPT=$(readlink -f "$0") SPATH=$(dirname "$SCRIPT") FLUX_SOURCE_DIR="$SPATH"/.. fi fi "${PYTHON:-python3}" -S "${FLUX_SOURCE_DIR}/t/scripts/run_timeout.py" "$FLUX_TEST_TIMEOUT" "$@" else "$@" fi echo $? ) | LC_ALL=C ${AM_TAP_AWK-awk} \ -v me="$me" \ -v test_script_name="$test_name" \ -v log_file="$log_file" \ -v trs_file="$trs_file" \ -v expect_failure="$expect_failure" \ -v merge="$merge" \ -v ignore_exit="$ignore_exit" \ -v comments="$comments" \ -v diag_string="$diag_string" \ -v quiet="$TAP_DRIVER_QUIET" \ ' # TODO: the usages of "cat >&3" below could be optimized when using # GNU awk, and/on on systems that supports /dev/fd/. # Implementation note: in what follows, `result_obj` will be an # associative array that (partly) simulates a TAP result object # from the `TAP::Parser` perl module. ## ----------- ## ## FUNCTIONS ## ## ----------- ## function fatal(msg) { print me ": " msg | "cat >&2" exit 1 } function abort(where) { fatal("internal error " where) } # Convert a boolean to a "yes"/"no" string. function yn(bool) { return bool ? "yes" : "no"; } function add_test_result(result) { if (!test_results_index) test_results_index = 0 test_results_list[test_results_index] = result test_results_index += 1 test_results_seen[result] = 1; } # Whether the test script should be re-run by "make recheck". function must_recheck() { for (k in test_results_seen) if (k != "XFAIL" && k != "PASS" && k != "SKIP") return 1 return 0 } # Whether the content of the log file associated to this test should # be copied into the "global" test-suite.log. function copy_in_global_log() { for (k in test_results_seen) if (k != "PASS") return 1 return 0 } function get_global_test_result() { if ("ERROR" in test_results_seen) return "ERROR" if ("FAIL" in test_results_seen || "XPASS" in test_results_seen) return "FAIL" all_skipped = 1 for (k in test_results_seen) if (k != "SKIP") all_skipped = 0 if (all_skipped) return "SKIP" return "PASS"; } function summarize_global_test_result() { i = 0 for (k in test_results_list) { i += 1 totals[ test_results_list[k] ] += 1 } res = sprintf ("N=%-3d PASS=%-3d FAIL=%d SKIP=%d XPASS=%d XFAIL=%d", i, totals["PASS"], totals["FAIL"], totals["SKIP"], totals["XPASS"], totals["XFAIL"]) return res } function stringify_result_obj(result_obj) { if (result_obj["is_unplanned"] || result_obj["number"] != testno) return "ERROR" if (plan_seen == LATE_PLAN) return "ERROR" if (result_obj["directive"] == "TODO") return result_obj["is_ok"] ? "XPASS" : "XFAIL" if (result_obj["directive"] == "SKIP") return result_obj["is_ok"] ? "SKIP" : COOKED_FAIL; if (length(result_obj["directive"])) abort("in function stringify_result_obj()") return result_obj["is_ok"] ? COOKED_PASS : COOKED_FAIL } function decorate_result(result) { color_name = color_for_result[result] if (color_name) return color_map[color_name] "" result "" color_map["std"] # If we are not using colorized output, or if we do not know how # to colorize the given result, we should return it unchanged. return result } function report(result, details) { if (result ~ /^(X?(PASS|FAIL)|SKIP|ERROR)/) { msg = ": " test_script_name add_test_result(result) } else if (result == "#") { msg = " " test_script_name ":" } else { abort("in function report()") } if (length(details)) msg = msg " " details # Output on console might be colorized. if (!quiet || result ~ /^(FAIL|ERROR)/) print decorate_result(result) msg # Log the result in the log file too, to help debugging (this is # especially true when said result is a TAP error or "Bail out!"). print result msg | "cat >&3"; } function testsuite_error(error_message) { report("ERROR", "- " error_message) } function handle_tap_result() { details = result_obj["number"]; if (length(result_obj["description"])) details = details " " result_obj["description"] if (plan_seen == LATE_PLAN) { details = details " # AFTER LATE PLAN"; } else if (result_obj["is_unplanned"]) { details = details " # UNPLANNED"; } else if (result_obj["number"] != testno) { details = sprintf("%s # OUT-OF-ORDER (expecting %d)", details, testno); } else if (result_obj["directive"]) { details = details " # " result_obj["directive"]; if (length(result_obj["explanation"])) details = details " " result_obj["explanation"] } report(stringify_result_obj(result_obj), details) } # `skip_reason` should be empty whenever planned > 0. function handle_tap_plan(planned, skip_reason) { planned += 0 # Avoid getting confused if, say, `planned` is "00" if (length(skip_reason) && planned > 0) abort("in function handle_tap_plan()") if (plan_seen) { # Error, only one plan per stream is acceptable. testsuite_error("multiple test plans") return; } planned_tests = planned # The TAP plan can come before or after *all* the TAP results; we speak # respectively of an "early" or a "late" plan. If we see the plan line # after at least one TAP result has been seen, assume we have a late # plan; in this case, any further test result seen after the plan will # be flagged as an error. plan_seen = (testno >= 1 ? LATE_PLAN : EARLY_PLAN) # If testno > 0, we have an error ("too many tests run") that will be # automatically dealt with later, so do not worry about it here. If # $plan_seen is true, we have an error due to a repeated plan, and that # has already been dealt with above. Otherwise, we have a valid "plan # with SKIP" specification, and should report it as a particular kind # of SKIP result. if (planned == 0 && testno == 0) { if (length(skip_reason)) skip_reason = "- " skip_reason; report("SKIP", skip_reason); } } function extract_tap_comment(line) { if (index(line, diag_string) == 1) { # Strip leading `diag_string` from `line`. line = substr(line, length(diag_string) + 1) # And strip any leading and trailing whitespace left. sub("^[ \t]*", "", line) sub("[ \t]*$", "", line) # Return what is left (if any). return line; } return ""; } # When this function is called, we know that line is a TAP result line, # so that it matches the (perl) RE "^(not )?ok\b". function setup_result_obj(line) { # Get the result, and remove it from the line. result_obj["is_ok"] = (substr(line, 1, 2) == "ok" ? 1 : 0) sub("^(not )?ok[ \t]*", "", line) # If the result has an explicit number, get it and strip it; otherwise, # automatically assing the next progresive number to it. if (line ~ /^[0-9]+$/ || line ~ /^[0-9]+[^a-zA-Z0-9_]/) { match(line, "^[0-9]+") # The final `+ 0` is to normalize numbers with leading zeros. result_obj["number"] = substr(line, 1, RLENGTH) + 0 line = substr(line, RLENGTH + 1) } else { result_obj["number"] = testno } if (plan_seen == LATE_PLAN) # No further test results are acceptable after a "late" TAP plan # has been seen. result_obj["is_unplanned"] = 1 else if (plan_seen && testno > planned_tests) result_obj["is_unplanned"] = 1 else result_obj["is_unplanned"] = 0 # Strip trailing and leading whitespace. sub("^[ \t]*", "", line) sub("[ \t]*$", "", line) # This will have to be corrected if we have a "TODO"/"SKIP" directive. result_obj["description"] = line result_obj["directive"] = "" result_obj["explanation"] = "" if (index(line, "#") == 0) return # No possible directive, nothing more to do. # Directives are case-insensitive. rx = "[ \t]*#[ \t]*([tT][oO][dD][oO]|[sS][kK][iI][pP])[ \t]*" # See whether we have the directive, and if yes, where. pos = match(line, rx "$") if (!pos) pos = match(line, rx "[^a-zA-Z0-9_]") # If there was no TAP directive, we have nothing more to do. if (!pos) return # Let`s now see if the TAP directive has been escaped. For example: # escaped: ok \# SKIP # not escaped: ok \\# SKIP # escaped: ok \\\\\# SKIP # not escaped: ok \ # SKIP if (substr(line, pos, 1) == "#") { bslash_count = 0 for (i = pos; i > 1 && substr(line, i - 1, 1) == "\\"; i--) bslash_count += 1 if (bslash_count % 2) return # Directive was escaped. } # Strip the directive and its explanation (if any) from the test # description. result_obj["description"] = substr(line, 1, pos - 1) # Now remove the test description from the line, that has been dealt # with already. line = substr(line, pos) # Strip the directive, and save its value (normalized to upper case). sub("^[ \t]*#[ \t]*", "", line) result_obj["directive"] = toupper(substr(line, 1, 4)) line = substr(line, 5) # Now get the explanation for the directive (if any), with leading # and trailing whitespace removed. sub("^[ \t]*", "", line) sub("[ \t]*$", "", line) result_obj["explanation"] = line } function get_test_exit_message(status) { if (status == 0) return "" if (status !~ /^[1-9][0-9]*$/) abort("getting exit status") if (status < 127) exit_details = "" else if (status == 127) exit_details = " (command not found?)" else if (status >= 128 && status <= 255) exit_details = sprintf(" (terminated by signal %d?)", status - 128) else if (status > 256 && status <= 384) # We used to report an "abnormal termination" here, but some Korn # shells, when a child process die due to signal number n, can leave # in $? an exit status of 256+n instead of the more standard 128+n. # Apparently, both behaviours are allowed by POSIX (2008), so be # prepared to handle them both. See also Austing Group report ID # 0000051 exit_details = sprintf(" (terminated by signal %d?)", status - 256) else # Never seen in practice. exit_details = " (abnormal termination)" return sprintf("exited with status %d%s", status, exit_details) } function write_test_results() { print ":global-test-result: " get_global_test_result() > trs_file print ":recheck: " yn(must_recheck()) > trs_file print ":copy-in-global-log: " yn(copy_in_global_log()) > trs_file for (i = 0; i < test_results_index; i += 1) print ":test-result: " test_results_list[i] > trs_file close(trs_file); } BEGIN { ## ------- ## ## SETUP ## ## ------- ## '"$init_colors"' # Properly initialized once the TAP plan is seen. planned_tests = 0 COOKED_PASS = expect_failure ? "XPASS": "PASS"; COOKED_FAIL = expect_failure ? "XFAIL": "FAIL"; # Enumeration-like constants to remember which kind of plan (if any) # has been seen. It is important that NO_PLAN evaluates "false" as # a boolean. NO_PLAN = 0 EARLY_PLAN = 1 LATE_PLAN = 2 testno = 0 # Number of test results seen so far. bailed_out = 0 # Whether a "Bail out!" directive has been seen. # Whether the TAP plan has been seen or not, and if yes, which kind # it is ("early" is seen before any test result, "late" otherwise). plan_seen = NO_PLAN ## --------- ## ## PARSING ## ## --------- ## is_first_read = 1 while (1) { # Involutions required so that we are able to read the exit status # from the last input line. st = getline if (st < 0) # I/O error. fatal("I/O error while reading from input stream") else if (st == 0) # End-of-input { if (is_first_read) abort("in input loop: only one input line") break } if (is_first_read) { is_first_read = 0 nextline = $0 continue } else { curline = nextline nextline = $0 $0 = curline } # Copy any input line verbatim into the log file. print | "cat >&3" # Parsing of TAP input should stop after a "Bail out!" directive. if (bailed_out) continue # TAP test result. if ($0 ~ /^(not )?ok$/ || $0 ~ /^(not )?ok[^a-zA-Z0-9_]/) { testno += 1 setup_result_obj($0) handle_tap_result() } # TAP plan (normal or "SKIP" without explanation). else if ($0 ~ /^1\.\.[0-9]+[ \t]*$/) { # The next two lines will put the number of planned tests in $0. sub("^1\\.\\.", "") sub("[^0-9]*$", "") handle_tap_plan($0, "") continue } # TAP "SKIP" plan, with an explanation. else if ($0 ~ /^1\.\.0+[ \t]*#/) { # The next lines will put the skip explanation in $0, stripping # any leading and trailing whitespace. This is a little more # tricky in truth, since we want to also strip a potential leading # "SKIP" string from the message. sub("^[^#]*#[ \t]*(SKIP[: \t][ \t]*)?", "") sub("[ \t]*$", ""); handle_tap_plan(0, $0) } # "Bail out!" magic. # Older versions of prove and TAP::Harness (e.g., 3.17) did not # recognize a "Bail out!" directive when preceded by leading # whitespace, but more modern versions (e.g., 3.23) do. So we # emulate the latter, "more modern" behaviour. else if ($0 ~ /^[ \t]*Bail out!/) { bailed_out = 1 # Get the bailout message (if any), with leading and trailing # whitespace stripped. The message remains stored in `$0`. sub("^[ \t]*Bail out![ \t]*", ""); sub("[ \t]*$", ""); # Format the error message for the bailout_message = "Bail out!" if (length($0)) bailout_message = bailout_message " " $0 testsuite_error(bailout_message) } # Maybe we have too look for dianogtic comments too. else if (comments != 0) { comment = extract_tap_comment($0); if (length(comment)) report("#", comment); } } ## -------- ## ## FINISH ## ## -------- ## # In quiet mode, issue summary now: if (quiet) { printf ("%26s: %5s: %s\n", test_script_name, decorate_result(get_global_test_result()), summarize_global_test_result()) } # A "Bail out!" directive should cause us to ignore any following TAP # error, as well as a non-zero exit status from the TAP producer. if (!bailed_out) { if (!plan_seen) { testsuite_error("missing test plan") } else if (planned_tests != testno) { bad_amount = testno > planned_tests ? "many" : "few" testsuite_error(sprintf("too %s tests run (expected %d, got %d)", bad_amount, planned_tests, testno)) } if (!ignore_exit) { # Fetch exit status from the last line. exit_message = get_test_exit_message(nextline) if (exit_message) testsuite_error(exit_message) } } write_test_results() exit 0 } # End of "BEGIN" block. ' # TODO: document that we consume the file descriptor 3 :-( } 3>"$log_file" test $? -eq 0 || fatal "I/O or internal error" # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: powerman-2.4.4/config/x_ac_check_cond_lib.m4000066400000000000000000000031241467035776500210040ustar00rootroot00000000000000##***************************************************************************** ## $Id: x_ac_check_cond_lib.m4 391 2005-02-10 02:31:11Z dun $ ##***************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_CHECK_COND_LIB(library, function) # # DESCRIPTION: # Check whether a program can be linked with to get . # Like AC_CHECK_LIB(), except that if the check succeeds, HAVE_LIB # will be defined and a shell variable LIB containing "-l" # will be substituted via AC_SUBST(). # # In other words, this is just like the default action of AC_CHECK_LIB(), # except that instead of modifying LIBS (which will affect the linking of # all executables), the shell variable LIB is defined so it can be # added to the linking of just those executables needing this library. # Also note that this checks to see if the library is even needed at all. ##***************************************************************************** AC_DEFUN([X_AC_CHECK_COND_LIB], [ AC_CACHE_CHECK( [for $2 in default libs], [x_ac_cv_lib_none_$2], [ AC_LINK_IFELSE( [AC_LANG_CALL([], [$2])], AS_VAR_SET(x_ac_cv_lib_none_$2, yes), AS_VAR_SET(x_ac_cv_lib_none_$2, no) )] ) AS_IF([test AS_VAR_GET(x_ac_cv_lib_none_$2) = no], AC_CHECK_LIB( [$1], [$2], [ AH_CHECK_LIB([$1]) AS_TR_CPP([LIB$1])="-l$1"; AC_SUBST(AS_TR_CPP([LIB$1])) AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_LIB$1])) ] ) )] ) powerman-2.4.4/config/x_ac_expand_install_dirs.m4000066400000000000000000000073371467035776500221360ustar00rootroot00000000000000##***************************************************************************** ## $Id: x_ac_expand_install_dirs.m4 494 2006-05-08 22:59:28Z dun $ ##***************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_EXPAND_INSTALL_DIRS # # DESCRIPTION: # Expand the installation directory variables. ##***************************************************************************** AC_DEFUN([X_AC_EXPAND_INSTALL_DIRS], [ AC_MSG_CHECKING([installation directory variables]) _x_ac_expand_install_dirs_prefix="$prefix" test "$prefix" = NONE && prefix="$ac_default_prefix" _x_ac_expand_install_dirs_exec_prefix="$exec_prefix" test "$exec_prefix" = NONE && exec_prefix="$prefix" adl_RECURSIVE_EVAL(["$prefix"], [X_PREFIX]) AC_DEFINE_UNQUOTED([X_PREFIX], ["$X_PREFIX"], [Expansion of the "prefix" installation directory.]) AC_SUBST([X_PREFIX]) adl_RECURSIVE_EVAL(["$exec_prefix"], [X_EXEC_PREFIX]) AC_DEFINE_UNQUOTED([X_EXEC_PREFIX], ["$X_EXEC_PREFIX"], [Expansion of the "exec_prefix" installation directory.]) AC_SUBST([X_EXEC_PREFIX]) adl_RECURSIVE_EVAL(["$bindir"], [X_BINDIR]) AC_DEFINE_UNQUOTED([X_BINDIR], ["$X_BINDIR"], [Expansion of the "bindir" installation directory.]) AC_SUBST([X_BINDIR]) adl_RECURSIVE_EVAL(["$sbindir"], [X_SBINDIR]) AC_DEFINE_UNQUOTED([X_SBINDIR], ["$X_SBINDIR"], [Expansion of the "sbindir" installation directory.]) AC_SUBST([X_SBINDIR]) adl_RECURSIVE_EVAL(["$libexecdir"], [X_LIBEXECDIR]) AC_DEFINE_UNQUOTED([X_LIBEXECDIR], ["$X_LIBEXECDIR"], [Expansion of the "libexecdir" installation directory.]) AC_SUBST([X_LIBEXECDIR]) adl_RECURSIVE_EVAL(["$datadir"], [X_DATADIR]) AC_DEFINE_UNQUOTED([X_DATADIR], ["$X_DATADIR"], [Expansion of the "datadir" installation directory.]) AC_SUBST([X_DATADIR]) adl_RECURSIVE_EVAL(["$sysconfdir"], [X_SYSCONFDIR]) AC_DEFINE_UNQUOTED([X_SYSCONFDIR], ["$X_SYSCONFDIR"], [Expansion of the "sysconfdir" installation directory.]) AC_SUBST([X_SYSCONFDIR]) adl_RECURSIVE_EVAL(["$sharedstatedir"], [X_SHAREDSTATEDIR]) AC_DEFINE_UNQUOTED([X_SHAREDSTATEDIR], ["$X_SHAREDSTATEDIR"], [Expansion of the "sharedstatedir" installation directory.]) AC_SUBST([X_SHAREDSTATEDIR]) adl_RECURSIVE_EVAL(["$localstatedir"], [X_LOCALSTATEDIR]) AC_DEFINE_UNQUOTED([X_LOCALSTATEDIR], ["$X_LOCALSTATEDIR"], [Expansion of the "localstatedir" installation directory.]) AC_SUBST([X_LOCALSTATEDIR]) adl_RECURSIVE_EVAL(["$runstatedir"], [X_RUNSTATEDIR]) AC_DEFINE_UNQUOTED([X_RUNSTATEDIR], ["$X_RUNSTATEDIR"], [Expansion of the "runstatedir" installation directory.]) AC_SUBST([X_RUNSTATEDIR]) adl_RECURSIVE_EVAL(["$libdir"], [X_LIBDIR]) AC_DEFINE_UNQUOTED([X_LIBDIR], ["$X_LIBDIR"], [Expansion of the "libdir" installation directory.]) AC_SUBST([X_LIBDIR]) adl_RECURSIVE_EVAL(["$includedir"], [X_INCLUDEDIR]) AC_DEFINE_UNQUOTED([X_INCLUDEDIR], ["$X_INCLUDEDIR"], [Expansion of the "includedir" installation directory.]) AC_SUBST([X_INCLUDEDIR]) adl_RECURSIVE_EVAL(["$oldincludedir"], [X_OLDINCLUDEDIR]) AC_DEFINE_UNQUOTED([X_OLDINCLUDEDIR], ["$X_OLDINCLUDEDIR"], [Expansion of the "oldincludedir" installation directory.]) AC_SUBST([X_OLDINCLUDEDIR]) adl_RECURSIVE_EVAL(["$infodir"], [X_INFODIR]) AC_DEFINE_UNQUOTED([X_INFODIR], ["$X_INFODIR"], [Expansion of the "infodir" installation directory.]) AC_SUBST([X_INFODIR]) adl_RECURSIVE_EVAL(["$mandir"], [X_MANDIR]) AC_DEFINE_UNQUOTED([X_MANDIR], ["$X_MANDIR"], [Expansion of the "mandir" installation directory.]) AC_SUBST([X_MANDIR]) prefix="$_x_ac_expand_install_dirs_prefix" exec_prefix="$_x_ac_expand_install_dirs_exec_prefix" AC_MSG_RESULT([yes]) ]) powerman-2.4.4/configure.ac000066400000000000000000000056531467035776500156740ustar00rootroot00000000000000## # Prologue. ## AC_INIT([powerman], m4_esyscmd([git describe --always | awk '/.*/ {sub(/^v/, ""); printf "%s",$1; exit}'])) AC_CONFIG_AUX_DIR([config]) AC_CONFIG_MACRO_DIR([config]) AC_CONFIG_SRCDIR([NEWS.md]) AC_CANONICAL_TARGET LT_INIT ## # If runstatedir not explicitly set on command line, use '/run' as default # N.B. runstatedir is not set at all in autoconf < 2.70. ## if test "$runstatedir" = '${localstatedir}/run' || test -z "$runstatedir"; then AC_SUBST([runstatedir],[/run]) fi X_AC_EXPAND_INSTALL_DIRS ## # Automake support. ## AM_INIT_AUTOMAKE([subdir-objects foreign]) AM_SILENT_RULES([yes]) AC_CONFIG_HEADERS([config/config.h]) AM_MAINTAINER_MODE([enable]) ## # Checks for programs. ## AC_PROG_CC AX_COMPILER_VENDOR AS_CASE($ax_cv_c_compiler_vendor, [gnu], [ WARNING_CFLAGS="-Wall -Werror" ] [clang], [ WARNING_CFLAGS="-Wall -Werror -Wno-unknown-warning-option -Wno-error=unknown-warning-option" ] ) AC_SUBST([WARNING_CFLAGS]) AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_LEX([noyywrap]) AS_IF([test "x$LEX" = "x:"],AC_MSG_ERROR([could not find flex]),[]) AC_PROG_YACC # AC_PROG_YACC sets YACC=yacc when nothing is found, even yacc # Just assume bison is the preferred compiler-compiler and call yacc a failure AS_IF([test "x$YACC" = "xyacc"],AC_MSG_ERROR([could not find bison]),[]) AM_CONDITIONAL(WITH_GNU_LD, test "$with_gnu_ld" = "yes") ## # ## AC_CHECK_FILES(/dev/ptmx) AC_CHECK_FILES(/dev/ptc) ## # Checks for header files. ## AC_CHECK_HEADERS( \ poll.h \ sys/select.h \ sys/syscall.h \ ) ## # Checks for typedefs, structures, and compiler characteristics. ## AC_C_BIGENDIAN AC_TYPE_UID_T AC_C_CONST AC_CHECK_TYPES(socklen_t, [], [], [#include ]) ## # Check for httppower, genders ## AC_HTTPPOWER AC_REDFISHPOWER AC_SNMPPOWER AC_GENDERS ## # Check for systemd ## RRA_WITH_SYSTEMD_UNITDIR ## # Checks for library functions. ## AC_SEARCH_LIBS([bind],[socket]) AC_SEARCH_LIBS([gethostbyaddr],[nsl]) AC_WRAP AC_CHECK_FUNC([poll], AC_DEFINE([HAVE_POLL], [1], [Define if you have poll])) # for list.c, cbuf.c, hostlist.c, and wrappers.c */ AC_DEFINE(WITH_LSD_FATAL_ERROR_FUNC, 1, [Define lsd_fatal_error]) AC_DEFINE(WITH_LSD_NOMEM_ERROR_FUNC, 1, [Define lsd_fatal_error]) # whether to install pkg-config file for API AC_PKGCONFIG # what user and group to run daemon as AC_RUNAS ## # Epilogue. ## AC_CONFIG_FILES( \ Makefile \ examples/powerman_el72.spec \ src/Makefile \ src/liblsd/Makefile \ src/libczmq/Makefile \ src/libcommon/Makefile \ src/powerman/Makefile \ src/httppower/Makefile \ src/redfishpower/Makefile \ src/snmppower/Makefile \ src/plmpower/Makefile \ src/libtap/Makefile \ etc/Makefile \ etc/libpowerman.pc \ etc/powerman.service \ heartbeat/Makefile \ man/Makefile \ man/powerman.1 \ man/libpowerman.3 \ man/powerman.conf.5 \ man/powerman.dev.5 \ man/httppower.8 \ man/redfishpower.8 \ man/plmpower.8 \ man/powermand.8 \ t/Makefile \ ) AC_OUTPUT powerman-2.4.4/debian/000077500000000000000000000000001467035776500146175ustar00rootroot00000000000000powerman-2.4.4/debian/README.Debian000066400000000000000000000000001467035776500166460ustar00rootroot00000000000000powerman-2.4.4/debian/README.source000066400000000000000000000000001467035776500167640ustar00rootroot00000000000000powerman-2.4.4/debian/compat000066400000000000000000000000031467035776500160160ustar00rootroot0000000000000010 powerman-2.4.4/debian/control000066400000000000000000000006111467035776500162200ustar00rootroot00000000000000Source: powerman Section: devel Priority: optional Maintainer: Jim Garlick Standards-Version: 4.1.2 Build-Depends: debhelper (>= 10), bison, flex, libsnmp-dev, libcurl4-gnutls-dev, libgenders-dev Homepage: https://github.com/chaos/powerman Package: powerman Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Power Control Utility powerman-2.4.4/debian/copyright000066400000000000000000000021701467035776500165520ustar00rootroot00000000000000Files: * Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: powerman Source: Files: * Copyright: 2001 The Regents of the University of California Copyright: 2007 Lawrence Livermore National Security, LLC License: GPL-2+ Files: debian/* Copyright: 2024 Jim Garlick License: GPL-3+ This package 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 package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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 . On Debian systems, the complete text of the GNU General Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". powerman-2.4.4/debian/powerman-docs.docs000066400000000000000000000000161467035776500202440ustar00rootroot00000000000000README.Debian powerman-2.4.4/debian/rules000077500000000000000000000014441467035776500157020ustar00rootroot00000000000000#!/usr/bin/make -f # See debhelper(7) (uncomment to enable) # output every command that modifies files on the build system. #export DH_VERBOSE = 1 # see FEATURE AREAS in dpkg-buildflags(1) #export DEB_BUILD_MAINT_OPTIONS = hardening=+all # see ENVIRONMENT in dpkg-buildflags(1) # package maintainers to append CFLAGS #export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic # package maintainers to append LDFLAGS #export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed %: dh $@ override_dh_auto_configure: dh_auto_configure -- --with-systemdsystemunitdir=/lib/systemd/system --with-tcp-wrappers --with-genders --with-httppower --with-redfishpower --with-snmppower override_dh_autoreconf: @echo not running autogen.sh on dist product override_dh_auto_install: dh_auto_install find . -name '*.la' -delete powerman-2.4.4/debian/source/000077500000000000000000000000001467035776500161175ustar00rootroot00000000000000powerman-2.4.4/debian/source/format000066400000000000000000000000141467035776500173250ustar00rootroot000000000000003.0 (quilt) powerman-2.4.4/etc/000077500000000000000000000000001467035776500141505ustar00rootroot00000000000000powerman-2.4.4/etc/Makefile.am000066400000000000000000000035561467035776500162150ustar00rootroot00000000000000if HAVE_SYSTEMD systemdsystemunit_DATA = powerman.service endif if WITH_PKG_CONFIG pkgconfig_DATA = libpowerman.pc endif pkgsysconfdir = $(sysconfdir)/powerman pkgsysconf_DATA = \ powerman.conf.example \ devices/apc7900.dev \ devices/apc7900v3.dev \ devices/apc7920.dev \ devices/apc8941.dev \ devices/apc.dev \ devices/apc-snmp.dev \ devices/apcnew.dev \ devices/apcold.dev \ devices/apcpdu3.dev \ devices/apcpdu.dev \ devices/appro-greenblade.dev \ devices/appro-gb2.dev \ devices/baytech.dev \ devices/baytech-snmp.dev \ devices/baytech-rpc18d-nc.dev \ devices/baytech-rpc22.dev \ devices/baytech-rpc28-nc.dev \ devices/baytech-rpc3-nc.dev \ devices/cb-7050.dev \ devices/cyclades-pm8.dev \ devices/cyclades-pm10.dev \ devices/cyclades-pm20.dev \ devices/cyclades-pm42.dev \ devices/dli.dev \ devices/dli4.dev \ devices/eaton-revelation-snmp.dev \ devices/eaton-epdu-blue-switched.dev \ devices/hp3488.dev \ devices/hpilo.dev \ devices/hpmp.dev \ devices/hpmpblade.dev \ devices/hpmpcell.dev \ devices/hpmpdome.dev \ devices/ibmbladecenter.dev \ devices/icebox.dev \ devices/icebox3.dev \ devices/ics8064.dev \ devices/ilom.dev \ devices/lom.dev \ devices/ipmi.dev \ devices/ipmipower.dev \ devices/ipmipower-serial.dev \ devices/kvm.dev \ devices/kvm-ssh.dev \ devices/openbmc.dev \ devices/redfish-supermicro.dev \ devices/redfishpower-cray-r272z30.dev \ devices/redfishpower-supermicro.dev \ devices/redfishpower-cray-windom.dev \ devices/redfishpower-cray-ex.dev \ devices/redfishpower-cray-ex-rabbit.dev \ devices/phantom.dev \ devices/plmpower.dev \ devices/powerman.dev \ devices/rancid-cisco-poe.dev \ devices/rancid-edgemax-poe.dev \ devices/raritan-px4316.dev \ devices/raritan-px5523.dev \ devices/sentry_cdu.dev \ devices/swpdu.dev \ devices/wti.dev \ devices/wti-rps10.dev EXTRA_DIST = $(pkgsysconf_DATA) $(check_DATA) powerman-2.4.4/etc/devices/000077500000000000000000000000001467035776500155725ustar00rootroot00000000000000powerman-2.4.4/etc/devices/apc-snmp.dev000066400000000000000000000034601467035776500200130ustar00rootroot00000000000000# APC Masterswitch Plus via SNMP (also can drive with apcnew.dev) # Seems to require snmp v1 # Tricky: write 1 for on, 2 for off specification "apc-snmp" { timeout 10 # about 5 sec for cycle command plug name { "1" "2" "3" "4" "5" "6" "7" "8" } script login { expect "snmppower> " send "start_v1 private\n" expect "snmppower> " } script logout { send "finish\n" expect "snmppower> " } # PowerNet-MIB::sPDUMasterState.0 script status_all { send "get enterprises.318.1.1.4.2.2.0\n" expect "enterprises.318.1.1.4.2.2.0: (On|Off)[[:space:]]+(On|Off)[[:space:]]+(On|Off)[[:space:]]+(On|Off)[[:space:]]+(On|Off)[[:space:]]+(On|Off)[[:space:]]+(On|Off)[[:space:]]+(On|Off)[[:space:]]*\n" setplugstate "1" $1 off="Off" on="On" setplugstate "2" $2 off="Off" on="On" setplugstate "3" $3 off="Off" on="On" setplugstate "4" $4 off="Off" on="On" setplugstate "5" $5 off="Off" on="On" setplugstate "6" $6 off="Off" on="On" setplugstate "7" $7 off="Off" on="On" setplugstate "8" $8 off="Off" on="On" } # PowerNet-MIB::sPDUOutletControl.sPDUOutletControlTable. # sPDUOutletControlEntry.sPDUOutletCtl. script on { send "set enterprises.318.1.1.4.4.2.1.3.%s i 1\n" expect "enterprises.318.1.1.4.4.2.1.3.[1-8]: 1\n" expect "snmppower> " } script off { send "set enterprises.318.1.1.4.4.2.1.3.%s i 2\n" expect "enterprises.318.1.1.4.4.2.1.3.[1-8]: 2\n" expect "snmppower> " } script cycle { send "set enterprises.318.1.1.4.4.2.1.3.%s i 2\n" expect "enterprises.318.1.1.4.4.2.1.3.[1-8]: 2\n" expect "snmppower> " delay 5 send "set enterprises.318.1.1.4.4.2.1.3.%s i 1\n" expect "enterprises.318.1.1.4.4.2.1.3.[1-8]: 1\n" expect "snmppower> " } } powerman-2.4.4/etc/devices/apc.dev000066400000000000000000000101331467035776500170330ustar00rootroot00000000000000# # $Id$ # # APC MasterSwitch Plus # # Firmware rev may not be the best indicator of whether you need "apc" # or "apcnew" scripts. We have one data point for "apc": # # - Firmware: APP v2.0.0 / AOS v2.5.4 # specification "apc" { timeout 10 plug name { "1" "2" "3" "4" "5" "6" "7" "8" } script login { expect "\n" expect "User Name : " send "apc\r\n" expect "Password : " send "apc\r\n" expect "> " send "1\r\n" # device manager menu expect "> " send "1\r\n" # select master switch plus 1 expect "> " } script logout { send "4\r\n" } script status_all { send "\r\n" # refresh foreachplug { expect "([0-9]+)-[^\n]*(ON|OFF)[^\n]*\r\n" setplugstate $1 $2 on="ON" off="OFF" } expect "> " } script on { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "8\r\n" # cancel any pending delays expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Success\r\n" send "\r\n" expect "> " send "1\r\n" # immediate on expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Success\r\n" send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " } script on_all { send "9\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "8\r\n" # cancel any pending delays expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Success\r\n" send "\r\n" expect "> " send "1\r\n" # immediate on expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Success\r\n" send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " } script off { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "8\r\n" # cancel any pending delays expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Success\r\n" send "\r\n" expect "> " send "3\r\n" # immediate off expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Success\r\n" send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " } script off_all { send "9\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "8\r\n" # cancel any pending delays expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Success\r\n" send "\r\n" expect "> " send "3\r\n" # immediate off expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Success\r\n" send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " } # If outlet is initially off, "immediate reboot" (4) will leave it off. # This doesn't match PowerMan's semantics for cycle, therefore do explicit # immediate off + immediate on. script cycle { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "8\r\n" # cancel any pending delays expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Success\r\n" send "\r\n" expect "> " send "3\r\n" # immediate off expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Success\r\n" send "\r\n" expect "> " delay 4 send "1\r\n" # immediate on expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Success\r\n" send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " } script cycle_all { send "9\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "8\r\n" # cancel any pending delays expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Success\r\n" send "\r\n" expect "> " send "3\r\n" # immediate off expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Success\r\n" send "\r\n" expect "> " delay 4 send "1\r\n" # immediate on expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Success\r\n" send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " } } powerman-2.4.4/etc/devices/apc7900.dev000066400000000000000000000074361467035776500173670ustar00rootroot00000000000000# # $Id:$ # # Written by Martin K. Petersen # Based upon apcpdc.dev by Trent D'Hooge and Makia Minich # # APC MasterSwitch AP7900 (and most likely AP7901, AP7920 & AP7921) # - Firmware: APP v2.7.3 / AOS v2.7.0 # specification "apc7900" { timeout 10 plug name { "1" "2" "3" "4" "5" "6" "7" "8" } script login { expect "\rUser Name : " send "apc\r\n" expect "\rPassword : " send "apc\r\n" expect "> " send "1\r\n" # device manager menu expect "> " send "3\r\n" # outlet control/configuration expect "> " } script logout { send "\033" expect "> " send "\033" expect "> " send "4\r\n" } script status_all { send "\r\n" # refresh foreachplug { expect "([0-9]+)-[^\n]*(ON|OFF)[^\n]*\r\n" setplugstate $1 $2 on="ON" off="OFF" } expect "> " } script on { send "%s\r\n" expect "> " send "1\r\n" # select control outlet expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "1\r\n" # immediate on expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" send "\r\n" expect "> " } script on_all { send "9\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "4\r\n" # delayed on expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" send "\r\n" expect "> " } script off { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "2\r\n" # immediate off expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" send "\r\n" expect "> " } script off_all { send "9\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "5\r\n" # delayed off expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" send "\r\n" expect "> " } # If outlet is initially off, "immediate reboot" (4) will leave it off. # This doesn't match PowerMan's semantics for cycle, therefore do explicit # immediate off + immediate on. script cycle { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "2\r\n" # immediate off expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " delay 4 send "1\r\n" # immediate on expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" send "\r\n" } script cycle_all { send "9\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "5\r\n" # delayed off expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " delay 4 send "4\r\n" # delayed on expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" send "\r\n" expect "> " } } powerman-2.4.4/etc/devices/apc7900v3.dev000066400000000000000000000074271467035776500176400ustar00rootroot00000000000000# # APC MasterSwitch AP7900 (and most likely AP7901, AP7920 & AP7921) # - Firmware: APP v3.7.0 / AOS v3.7.0 # # Firmware version 3 changes contributed by Py Watson. # specification "apc7900v3" { timeout 10 plug name { "1" "2" "3" "4" "5" "6" "7" "8" } script login { expect "\rUser Name : " send "apc\r\n" expect "\rPassword : " send "apc\r\n" expect "> " send "1\r\n" # device manager menu expect "> " send "2\r\n" # outlet management expect "> " send "1\r\n" # Outlet Control/Configuration expect "> " } script logout { send "\033" expect "> " send "\033" expect "> " send "4\r\n" } script status_all { send "\r\n" # refresh foreachplug { expect "([0-9]+)-[^\n]*(ON|OFF)[^\n]*\r\n" setplugstate $1 $2 on="ON" off="OFF" } expect "> " } script on { send "%s\r\n" expect "> " send "1\r\n" # select control outlet expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "1\r\n" # immediate on expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" send "\r\n" expect "> " } script on_all { send "9\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "4\r\n" # delayed on expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" send "\r\n" expect "> " } script off { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "2\r\n" # immediate off expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" send "\r\n" expect "> " } script off_all { send "9\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "5\r\n" # delayed off expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" send "\r\n" expect "> " } # If outlet is initially off, "immediate reboot" (4) will leave it off. # This doesn't match PowerMan's semantics for cycle, therefore do explicit # immediate off + immediate on. script cycle { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "2\r\n" # immediate off expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " delay 4 send "1\r\n" # immediate on expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" send "\r\n" } script cycle_all { send "9\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "5\r\n" # delayed off expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " delay 4 send "4\r\n" # delayed on expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" send "\r\n" expect "> " } } powerman-2.4.4/etc/devices/apc7920.dev000066400000000000000000000032521467035776500173610ustar00rootroot00000000000000# # $Id:$ # Written by Manfred Gruber # # Based upon apc7900.dev by Martin K. Petersen # Based upon apcpdc.dev by Trent D'Hooge and Makia Minich # # APC MasterSwitch AP7920 # - Firmware: APP v3.3.3 / AOS v3.3.4 # specification "apc7920" { timeout 3 plug name { "1" "2" "3" "4" "5" "6" "7" "8" } script login { expect "\rUser Name : " send "apc\r\n" expect "\rPassword : " send "apc\r\n" expect "> " } script logout { send "\033" expect "> " send "\033" expect "> " send "4\r\n" } script on { send "1\r\n" # device manager menu expect "> " send "2\r\n" # Outlet Management expect "> " send "1\r\n" # outlet control/configuration expect "> " send "%s\r\n" # Nr Outlet X expect "> " send "1\r\n" # select control outlet expect "> " send "1\r\n" # immediate on expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " send "\033" expect "> " send "\033" expect "> " send "\033" expect "> " send "\r\n" expect "> " } script off { send "1\r\n" # device manager menu expect "> " send "2\r\n" # Outlet Management expect "> " send "1\r\n" # outlet control/configuration expect "> " send "%s\r\n" # Nr Outlet X expect "> " send "1\r\n" # select control outlet expect "> " send "2\r\n" # immediate off expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " send "\033" expect "> " send "\033" expect "> " send "\033" expect "> " send "\r\n" expect "> " } } powerman-2.4.4/etc/devices/apc8941.dev000066400000000000000000000032161467035776500173650ustar00rootroot00000000000000# # Derived from apcpdu3.dev, but updated for new firmware # # - Firmware: rpdu2g v6.0.9 / AOS v6.1.3 # specification "apc8941" { timeout 10 plug name { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "20" "21" "22" "23" "24" } script login { expect "snmppower> " send "start_v2c private\n" expect "snmppower> " } script logout { send "finish" expect "snmppower> " } script status { send "get enterprises.318.1.1.26.9.2.3.1.5.%s\n" expect "enterprises.318.1.1.26.9.2.3.1.5.([0-9]+): (1|2)" setplugstate $1 $2 on="2" off="1" expect "snmppower>" } script on { send "set enterprises.318.1.1.26.9.2.4.1.5.%s i 1\n" expect "enterprises.318.1.1.26.9.2.4.1.5.[0-9]+: 1\n" expect "snmppower> " delay 0.3 } script off { send "set enterprises.318.1.1.26.9.2.4.1.5.%s i 2\n" expect "enterprises.318.1.1.26.9.2.4.1.5.[0-9]+: 2\n" expect "snmppower> " } script cycle { send "set enterprises.318.1.1.26.9.2.4.1.5.%s i 2\n" expect "enterprises.318.1.1.26.9.2.4.1.5.[0-9]+: 2\n" expect "snmppower> " delay 5 send "set enterprises.318.1.1.26.9.2.4.1.5.%s i 1\n" expect "enterprises.318.1.1.26.9.2.4.1.5.[0-9]+: 1\n" expect "snmppower> " delay 0.3 } } powerman-2.4.4/etc/devices/apcnew.dev000066400000000000000000000066651467035776500175640ustar00rootroot00000000000000# # $Id$ # # APC MasterSwitch Plus # # Firmware rev may not be the best indicator of whether you need "apc" # or "apcnew" scripts. We have two data points for "apcnew": # # - Firmware: APP v2.2.0 / AOS v3.0.3 # - Firmware: APP v2.0.2 / AOS v2.5.3 # specification "apcnew" { timeout 10 plug name { "1" "2" "3" "4" "5" "6" "7" "8" } script login { expect "\n" expect "User Name : " send "apc\r\n" expect "Password : " send "apc\r\n" expect "> " send "1\r\n" # device manager menu expect "> " } script logout { send "\033\r\n" } script status_all { send "\r\n" # refresh foreachplug { expect "([0-9]+)-[^\n]*(ON|OFF)[^\n]*\r\n" setplugstate $1 $2 on="ON" off="OFF" } expect "> " } script on { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "1\r\n" # immediate on expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Command successfully issued.\r\n" send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " } script on_all { send "9\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "1\r\n" # immediate on expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Command successfully issued.\r\n" send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " } script off { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "2\r\n" # immediate off expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Command successfully issued.\r\n" send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " } script off_all { send "9\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "2\r\n" # immediate off expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Command successfully issued.\r\n" send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " } # If outlet is initially off, "immediate reboot" (4) will leave it off. # This doesn't match PowerMan's semantics for cycle, therefore do explicit # immediate off + immediate on. script cycle { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "2\r\n" # immediate off expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Command successfully issued.\r\n" send "\r\n" expect "> " delay 4 send "1\r\n" # immediate on expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Command successfully issued.\r\n" send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " } script cycle_all { send "9\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "8\r\n" # cancel any pending delays expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Command successfully issued.\r\n" send "\r\n" expect "> " send "2\r\n" # immediate off expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Command successfully issued.\r\n" send "\r\n" expect "> " delay 4 send "1\r\n" # immediate on expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "Command successfully issued.\r\n" send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " } } powerman-2.4.4/etc/devices/apcold.dev000066400000000000000000000066621467035776500175460ustar00rootroot00000000000000# # $Id:$ # # apparently there is an apc interface older than "apc.dev" # # This talks to: # # Model Number : AP9210 Serial Number : WA9903036579 # Firmware Revision : v1.1.1 Hardware Revision : C4 # Manufacture Date : 01/14/1999 # # specification "apcold" { timeout 10 plug name { "1" "2" "3" "4" "5" "6" "7" "8" } script login { expect "\n" expect "User Name : " send "apc\r\n" expect "Password : " send "apc\r\n" expect "> " send "1\r\n" # outlet manager menu expect "> " } script logout { send "\033" # ESC back to control console menu expect "> " send "4\r\n" } script status_all { send "9\r\n" # master/pdu control expect "> " send "1\r\n" # control of master pdu foreachplug { expect "([1-8]+):(ON|OFF)[^\n]*\r\n" setplugstate $1 $2 on="ON" off="OFF" } expect "> " send "\033" # ESC back to master/pdu expect "> " send "\033" # ESC back to outlet manager menu expect "> " } script on { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "1\r\n" # immediate on expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "successfully!\r\n" send "\r\n" expect "> " send "\033" # ESC back to outlet expect "> " send "\033" # ESC back to outlet manager expect "> " } script on_all { send "9\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "1\r\n" # immediate on expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "successfully!\r\n" send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " } script off { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "2\r\n" # immediate off expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "successfully!\r\n" send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " } script off_all { send "9\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "2\r\n" # immediate off expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "successfully!\r\n" send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " } # If outlet is initially off, "immediate reboot" (4) will leave it off. # This doesn't match PowerMan's semantics for cycle, therefore do explicit # immediate off + immediate on. script cycle { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "2\r\n" # immediate off expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "successfully!\r\n" send "\r\n" expect "> " delay 4 send "1\r\n" # immediate on expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "successfully!\r\n" send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " } script cycle_all { send "9\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "2\r\n" # immediate off expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "successfully!\r\n" send "\r\n" expect "> " delay 4 send "1\r\n" # immediate on expect "Enter 'YES' to continue or to cancel : " send "YES\r\n" expect "successfully!\r\n" send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "> " } } powerman-2.4.4/etc/devices/apcpdu.dev000066400000000000000000000104461467035776500175530ustar00rootroot00000000000000# # $Id:$ # # Written by Trent D'Hooge and Makia Minich # # Should support the following 24-plug APC Switched Rack PDU models: # AP7930, AP7932 # AP7940, AP7941 # AP7960, AP7961, AP7968, AP7990, AP7991, AP7998 # AP7951, AP7952, AP7953, AP7954 # # - Firmware: APP v2.6.5 / AOS v2.6.4 # specification "apcpdu" { timeout 10 plug name { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "20" "21" "22" "23" "24" } script login { expect "\n" expect "\rUser Name : " send "apc\r\n" expect "\rPassword : " send "apc\r\n" expect "> " send "1\r\n" # device manager menu expect "> " send "3\r\n" # outlet control/configuration expect "to continue..." send "\r\n" expect "> " } script logout { send "\033" expect "> " send "\033" expect "> " send "4\r\n" } script status_all { send "\r\n" # refresh send "\r\n" # to continue... (after plug 22) foreachplug { expect "([0-9])*[^\r\n]*(ON|OFF)\r\n" setplugstate $1 $2 on="ON" off="OFF" } expect "> " } script on { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "1\r\n" # immediate on expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "to continue..." send "\r\n" expect "> " } script on_all { send "25\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "4\r\n" # delayed on expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "to continue..." send "\r\n" expect "> " } script off { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "2\r\n" # immediate off expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "to continue..." send "\r\n" expect "> " } script off_all { send "25\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "5\r\n" # delayed off expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "to continue..." send "\r\n" expect "> " } # If outlet is initially off, "immediate reboot" (4) will leave it off. # This doesn't match PowerMan's semantics for cycle, therefore do explicit # immediate off + immediate on. script cycle { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "2\r\n" # immediate off expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " delay 4 send "1\r\n" # immediate on expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "to continue..." send "\r\n" } script cycle_all { send "25\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "5\r\n" # delayed off expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " delay 4 send "4\r\n" # delayed on expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "to continue..." send "\r\n" expect "> " } } powerman-2.4.4/etc/devices/apcpdu3.dev000066400000000000000000000101071467035776500176300ustar00rootroot00000000000000# # Derived from apcpdu.dev, but updated for new firmware # # - Firmware: APP v3.3.3 / AOS v3.3.4 # specification "apcpdu3" { timeout 10 plug name { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "20" "21" "22" "23" "24" } script login { expect "\n" expect "\rUser Name : " send "apc\r\n" expect "\rPassword : " send "apc\r\n" expect "> " send "1\r\n" # device manager menu expect "> " send "2\r\n" # outlet management expect "> " send "1\r\n" # Outlet Control/Configuration expect "to continue..." send "\r\n" expect "> " } script logout { send "\033" expect "> " send "\033" expect "> " send "4\r\n" } script status_all { send "\r\n" # refresh send "\r\n" # to continue... (after plug 22) foreachplug { expect "([0-9])*[^\r\n]*(ON|OFF)\r\n" setplugstate $1 $2 on="ON" off="OFF" } expect "> " } script on { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "1\r\n" # immediate on expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "to continue..." send "\r\n" expect "> " } script on_all { send "25\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "4\r\n" # delayed on expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "to continue..." send "\r\n" expect "> " } script off { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "2\r\n" # immediate off expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "to continue..." send "\r\n" expect "> " } script off_all { send "25\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "5\r\n" # delayed off expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "to continue..." send "\r\n" expect "> " } # If outlet is initially off, "immediate reboot" (4) will leave it off. # This doesn't match PowerMan's semantics for cycle, therefore do explicit # immediate off + immediate on. script cycle { send "%s\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "2\r\n" # immediate off expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " delay 4 send "1\r\n" # immediate on expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "to continue..." send "\r\n" } script cycle_all { send "25\r\n" expect "> " send "1\r\n" # select outlet control expect "> " send "7\r\n" # cancel any pending delays expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "5\r\n" # delayed off expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " delay 4 send "4\r\n" # delayed on expect "to cancel : " send "YES\r\n" expect "to continue..." send "\r\n" expect "> " send "\033" expect "> " send "\033" expect "to continue..." send "\r\n" expect "> " } } powerman-2.4.4/etc/devices/appro-gb2.dev000066400000000000000000000125641467035776500200730ustar00rootroot00000000000000# # GreenBlade Subrack # APPRO Inc. # # appro-gb2.dev,v 1.0 2010/07/19 16:05:34 Francis Lee (kolee@appro.com) # /usr/local/etc/powerman/appro-gb2.dev,v # # sr5110 : Standard 10 Nodes # sr5110_gpu : 5 Nodes with 5 GPU expansions # sr8116 : Standard 16 Nodes # sr8116_gpu : 8 Nodes with 8 GPU expansions # sr8104 : 2U 4 Nodes same as sr8104_gpu # specification "sr5110" { timeout 15.0 plug name { "01" "02" "03" "04" "05" "06" "07" "08" "09" "10" } script ping { send "\r" expect "-iSCB> " } script login { delay 0.5 send "\r" expect "-iSCB> " } script logout { send "exit\r" } script status_all { send "pmnode all\r" foreachplug { expect "node([0-9]+): (on|off|n/a)" setplugstate $1 $2 on="on" off="off" } expect "-iSCB> " } script status_beacon_all { send "pmled all\r" foreachplug { expect "node([0-9]+): (on|off|n/a)" setplugstate $1 $2 on="on" off="off" } expect "-iSCB> " } script on { send "power on %s\r" expect "-iSCB> " } script off { send "power off %s\r" expect "-iSCB> " } script cycle { send "power cycle %s\r" expect "-iSCB> " } script beacon_on { send "led on %s\r" expect "-iSCB> " } script beacon_off { send "led off %s\r" expect "-iSCB> " } script reset_all { send "power reset all\r" expect "-iSCB> " } script reset { send "power reset %s\r" expect "-iSCB> " } } specification "sr5110_gpu" { timeout 15.0 plug name { "01" "02" "03" "04" "05" } script ping { send "\r" expect "-iSCB> " } script login { delay 0.5 send "\r" expect "-iSCB> " } script logout { send "exit\r" } script status_all { send "pmnode all\r" foreachplug { expect "node([0-9]+): (on|off|n/a)" setplugstate $1 $2 on="on" off="off" } expect "-iSCB> " } script status_beacon_all { send "pmled all\r" foreachplug { expect "node([0-9]+): (on|off|n/a)" setplugstate $1 $2 on="on" off="off" } expect "-iSCB> " } script on { send "power on %s\r" expect "-iSCB> " } script off { send "power off %s\r" expect "-iSCB> " } script cycle { send "power cycle %s\r" expect "-iSCB> " } script beacon_on { send "led on %s\r" expect "-iSCB> " } script beacon_off { send "led off %s\r" expect "-iSCB> " } script reset_all { send "power reset all\r" expect "-iSCB> " } script reset { send "power reset %s\r" expect "-iSCB> " } } specification "sr8116" { timeout 15.0 plug name { "01" "02" "03" "04" "05" "06" "07" "08" "09" "10" "11" "12" "13" "14" "15" "16" } script ping { send "\r" expect "-iSCB> " } script login { delay 0.5 send "\r" expect "-iSCB> " } script logout { send "exit\r" } script status_all { send "pmnode all\r" foreachplug { expect "node([0-9]+): (on|off|n/a)" setplugstate $1 $2 on="on" off="off" } expect "-iSCB> " } script status_beacon_all { send "pmled all\r" foreachplug { expect "node([0-9]+): (on|off|n/a)" setplugstate $1 $2 on="on" off="off" } expect "-iSCB> " } script on { send "power on %s\r" expect "-iSCB> " } script off { send "power off %s\r" expect "-iSCB> " } script cycle { send "power cycle %s\r" expect "-iSCB> " } script beacon_on { send "led on %s\r" expect "-iSCB> " } script beacon_off { send "led off %s\r" expect "-iSCB> " } script reset_all { send "power reset all\r" expect "-iSCB> " } script reset { send "power reset %s\r" expect "-iSCB> " } } specification "sr8116_gpu" { timeout 15.0 plug name { "01" "02" "03" "04" } script ping { send "\r" expect "-iSCB> " } script login { delay 0.5 send "\r" expect "-iSCB> " } script logout { send "exit\r" } script status_all { send "pmnode all\r" foreachplug { expect "node([0-9]+): (on|off|n/a)" setplugstate $1 $2 on="on" off="off" } expect "-iSCB> " } script status_beacon_all { send "pmled all\r" foreachplug { expect "node([0-9]+): (on|off|n/a)" setplugstate $1 $2 on="on" off="off" } expect "-iSCB> " } script on { send "power on %s\r" expect "-iSCB> " } script off { send "power off %s\r" expect "-iSCB> " } script cycle { send "power cycle %s\r" expect "-iSCB> " } script beacon_on { send "led on %s\r" expect "-iSCB> " } script beacon_off { send "led off %s\r" expect "-iSCB> " } script reset_all { send "power reset all\r" expect "-iSCB> " } script reset { send "power reset %s\r" expect "-iSCB> " } } specification "sr8104" { timeout 15.0 plug name { "01" "02" "03" "04" } script ping { send "\r" expect "-iSCB> " } script login { delay 0.5 send "\r" expect "-iSCB> " } script logout { send "exit\r" } script status_all { send "pmnode all\r" foreachplug { expect "node([0-9]+): (on|off|n/a)" setplugstate $1 $2 on="on" off="off" } expect "-iSCB> " } script status_beacon_all { send "pmled all\r" foreachplug { expect "node([0-9]+): (on|off|n/a)" setplugstate $1 $2 on="on" off="off" } expect "-iSCB> " } script on { send "power on %s\r" expect "-iSCB> " } script off { send "power off %s\r" expect "-iSCB> " } script cycle { send "power cycle %s\r" expect "-iSCB> " } script beacon_on { send "led on %s\r" expect "-iSCB> " } script beacon_off { send "led off %s\r" expect "-iSCB> " } script reset_all { send "power reset all\r" expect "-iSCB> " } script reset { send "power reset %s\r" expect "-iSCB> " } } powerman-2.4.4/etc/devices/appro-greenblade.dev000066400000000000000000000104631467035776500215050ustar00rootroot00000000000000# # GreenBlade Subrack # APPRO Inc. # # appro-greenblade.dev,v 1.0 2010/07/19 16:05:34 Francis Lee (kolee@appro.com) # /usr/local/etc/powerman/appro-greenblade.dev,v # # iscb-gb : Standard 10 nodes # iscb-gbgpu : 5 nodes with 5 GPU expansions # iscb-hybrid : 6 nodes with 4 GPU expansions # specification "iscb-gb" { timeout 10.0 plug name { "01" "02" "03" "04" "05" "06" "07" "08" "09" "10" } script ping { send "\r\n" expect "iSCB-[0-9]+:[0-9]> " } script login { send "\r\n" delay 0.5 expect "Password: " send "111111\r\n" expect "iSCB-[0-9]+:[0-9]> " } script logout { send "exit\r\n" expect "ok" #expect "ok\niSCB-[0-9]+:[0-9]> " } script status_all { send "pmnode all\r\n" foreachplug { expect "node([0-9]+): (on|off|n/a)" setplugstate $1 $2 on="on" off="off" } expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script status_beacon_all { send "pmled all\r\n" foreachplug { expect "node([0-9]+): (on|off|n/a)" setplugstate $1 $2 on="on" off="off" } expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script on { send "on %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script off { send "off %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script cycle { send "cycle %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script beacon_on { send "led on %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script beacon_off { send "led off %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script reset_all { send "reset all\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script reset { send "reset %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } } specification "iscb-gbgpu" { timeout 10.0 plug name { "01" "02" "03" "04" "05" } script ping { send "\r\n" expect "iSCB-[0-9]+:[0-9]> " } script login { send "\r\n" delay 0.5 expect "Password: " send "111111\r\n" expect "iSCB-[0-9]+:[0-9]> " } script logout { send "exit\r\n" expect "ok" #expect "ok\niSCB-[0-9]+:[0-9]> " } script status_all { send "pmnode all\r\n" foreachplug { expect "node([0-9]+): (on|off|n/a)" setplugstate $1 $2 on="on" off="off" } expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script status_beacon_all { send "pmled all\r\n" foreachplug { expect "node([0-9]+): (on|off|n/a)" setplugstate $1 $2 on="on" off="off" } expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script on { send "on %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script off { send "off %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script cycle { send "cycle %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script beacon_on { send "led on %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script beacon_off { send "led off %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script reset_all { send "reset all\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script reset { send "reset %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } } specification "iscb-hybrid" { timeout 10.0 plug name { "01" "02" "03" "04" "05" "06" "07" } script ping { send "\r\n" expect "iSCB-[0-9]+:[0-9]> " } script login { send "\r\n" delay 0.5 expect "Password: " send "111111\r\n" expect "iSCB-[0-9]+:[0-9]> " } script logout { send "exit\r\n" expect "ok" #expect "ok\niSCB-[0-9]+:[0-9]> " } script status_all { send "pmnode all\r\n" foreachplug { expect "node([0-9]+): (on|off|n/a)" setplugstate $1 $2 on="on" off="off" } expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script status_beacon_all { send "pmled all\r\n" foreachplug { expect "node([0-9]+): (on|off|n/a)" setplugstate $1 $2 on="on" off="off" } expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script on { send "on %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script off { send "off %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script cycle { send "cycle %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script beacon_on { send "led on %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script beacon_off { send "led off %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script reset_all { send "reset all\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } script reset { send "reset %s\r\n" expect "ok" expect "iSCB-[0-9]+:[0-9]> " } } powerman-2.4.4/etc/devices/baytech-rpc18d-nc.dev000066400000000000000000000027471467035776500214200ustar00rootroot00000000000000# # $Id: baytech-rpc18d-nc.dev 964 2008-06-13 13:40:47Z garlick $ # # Baytech RPC18D-NC # # Default config, then disable confirmation, and disable status menu. # # Firmware version: F3.01 (C) 2000 # # Maybe it is accumulated serial noise or some other issue, but this # model seems to require a little handshake: # send "\r\n" # expect ".*RPC-18>" # before each command to avoid dropping the command. # specification "baytech-rpc18d-nc" { timeout 7 # about 5 sec for cycle command plug name { "1" "2" "3" "4" "5" "6" "7" "8" } script login { send "\r\n" expect ".*RPC-18>" } script logout { send "\r\n" expect ".*RPC-18>" send "exit\r\n" } script status_all { send "\r\n" expect ".*RPC-18>" send "status\r\n" foreachplug { expect "([0-9]+)\)\.*.*: (On|Off)" setplugstate $1 $2 on="On" off="Off" } expect "RPC-18>" } script on { send "\r\n" expect ".*RPC-18>" send "on %s\r\n" expect "RPC-18>" } script on_all { send "\r\n" expect ".*RPC-18>" send "on 0\r\n" expect "RPC-18>" } script off { send "\r\n" expect ".*RPC-18>" send "off %s\r\n" expect "RPC-18>" } script off_all { send "\r\n" expect ".*RPC-18>" send "off 0\r\n" expect "RPC-18>" } script cycle { send "\r\n" expect ".*RPC-18>" send "off %s\r\n" expect "RPC-18>" delay 4 send "on %s\r\n" expect "RPC-18>" } script cycle_all { send "\r\n" expect ".*RPC-18>" send "off 0\r\n" expect "RPC-18>" delay 4 send "on 0\r\n" expect "RPC-18>" } } powerman-2.4.4/etc/devices/baytech-rpc22.dev000066400000000000000000000042231467035776500206400ustar00rootroot00000000000000# # Baytech RPC22-20 # # Default config, then disable confirmation, and disable status menu. # # Firmware version: F1.10 (C) 2000 # # Maybe it is accumulated serial noise or some other issue, but this # model seems to require a little handshake: # send "\r\n" # expect ".*RPC-22>" # before each command to avoid dropping the command. # specification "baytech-rpc22" { timeout 10 # about 5 sec for cycle command plug name { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" } script login { send "\r\n" expect ".*RPC-22>" } script logout { send "\r\n" expect ".*RPC-22>" send "exit\r\n" } script status_all { send "\r\n" expect ".*RPC-22>" send "status\r\n" foreachplug { expect "Outlet[ ]+([0-9]+)[^:0-9]+: (On|Off)" setplugstate $1 $2 on="On" off="Off" } expect "RPC-22>" } script on { send "\r\n" expect ".*RPC-22>" send "on %s\r\n" expect "RPC-22>" } script on_all { send "\r\n" expect ".*RPC-22>" send "on 0\r\n" expect "RPC-22>" } script off { send "\r\n" expect ".*RPC-22>" send "off %s\r\n" expect "RPC-22>" } script off_all { send "\r\n" expect ".*RPC-22>" send "off 0\r\n" expect "RPC-22>" } script cycle { send "\r\n" expect ".*RPC-22>" send "off %s\r\n" expect "RPC-22>" delay 2 send "on %s\r\n" expect "RPC-22>" } script cycle_all { send "\r\n" expect ".*RPC-22>" send "off 0\r\n" expect "RPC-22>" delay 2 send "on 0\r\n" expect "RPC-22>" } } powerman-2.4.4/etc/devices/baytech-rpc28-nc.dev000066400000000000000000000031071467035776500212440ustar00rootroot00000000000000# # $Id$ # # Baytech RPC28-30NC # # Default config, then disable confirmation, and disable status menu. # # Firmware version: F3.01 (C) 2000 # # Maybe it is accumulated serial noise or some other issue, but this # model seems to require a little handshake: # send "\r\n" # expect ".*RPC-28[A]*>" # before each command to avoid dropping the command. # specification "baytech-rpc28-nc" { timeout 10 # about 5 sec for cycle command plug name { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "20" } script login { send "\r\n" expect ".*RPC-28[A]*>" } script logout { send "\r\n" expect ".*RPC-28[A]*>" send "exit\r\n" } script status_all { send "\r\n" expect ".*RPC-28[A]*>" send "status\r\n" foreachplug { expect "Outlet[ ]+([0-9]+)[^:0-9]+: (On|Off)" setplugstate $1 $2 on="On" off="Off" } expect "RPC-28[A]*>" } script on { send "\r\n" expect ".*RPC-28[A]*>" send "on %s\r\n" expect "RPC-28[A]*>" } script on_all { send "\r\n" expect ".*RPC-28[A]*>" send "on 0\r\n" expect "RPC-28[A]*>" } script off { send "\r\n" expect ".*RPC-28[A]*>" send "off %s\r\n" expect "RPC-28[A]*>" } script off_all { send "\r\n" expect ".*RPC-28[A]*>" send "off 0\r\n" expect "RPC-28[A]*>" } script cycle { send "\r\n" expect ".*RPC-28[A]*>" send "off %s\r\n" expect "RPC-28[A]*>" delay 4 send "on %s\r\n" expect "RPC-28[A]*>" } script cycle_all { send "\r\n" expect ".*RPC-28[A]*>" send "off 0\r\n" expect "RPC-28[A]*>" delay 4 send "on 0\r\n" expect "RPC-28[A]*>" } } powerman-2.4.4/etc/devices/baytech-rpc3-nc.dev000066400000000000000000000031001467035776500211460ustar00rootroot00000000000000# # $Id$ # # Baytech RPC3-20NC # # Tested the following firmware versions: # RPC3-NC Series (C) 2002 by BayTech F4.00 # RPC-3/4(A)DE Series (C) 2004 BayTech F1.08 # RPC-3/4(A)DE Series (C) 2004 BayTech F1.09 # # Note: # Type ";;;;;" to access "network interface module". # Prompt is not returned until device is ready to accept another command. # # Assumes: # Command confirmation : disabled # Status menu : disabled # No access control # No idle timeout # No active restore (causes disconnections) # specification "baytech-rpc3-nc" { timeout 10 # about 5 sec for cycle command plug name { "1" "2" "3" "4" "5" "6" "7" "8" } script login { send "\r\n" expect ">" } script logout { send "exit\r\n" } script status_all { # XXX this works around bug where foreachplug # counter doesn't reset when script restarts after reconnect send "\r\n" expect ">" # XXX end workaround send "status\r\n" foreachplug { expect "Outlet ([0-9]+)[^:0-9]+: (On|Off)" setplugstate $1 $2 on="On" off="Off" } expect ">" } script on { send "on %s\r\n" expect ">" } script on_all { send "on 0\r\n" expect ">" } script off { send "off %s\r\n" expect ">" } script off_all { send "off 0\r\n" expect ">" } # If outlet is initially off, "reboot" will leave it off. # This doesn't match PowerMan's semantics for cycle, so explicitly power # off then on. script cycle { send "off %s\r\n" expect ">" delay 4 send "on %s\r\n" expect ">" } script cycle_all { send "off 0\r\n" expect ">" delay 4 send "on 0\r\n" expect ">" } } powerman-2.4.4/etc/devices/baytech-snmp.dev000066400000000000000000000032511467035776500206650ustar00rootroot00000000000000# Baytech RPC3-NC via SNMP (also can drive with baytech-rpc3-nc.dev) # # Snmp v1 or v2c works. # # N.B. Occasionally snmp agent locks up and must be restarted by telnet or # serial: ;;;;; then Network Interface Module Login, then Unit Reset. # # Example device entry: # device "b" "baytech-snmp" "/usr/sbin/snmppower -h 192.168.1.95|&" specification "baytech-snmp" { timeout 10 # about 5 sec for cycle command plug name { "1" "2" "3" "4" "5" "6" "7" "8" } script login { expect "snmppower> " send "start_v2c private\n" expect "snmppower> " } script logout { send "finish\n" expect "snmppower> " } script status_all { send "get enterprises.4779.1.3.5.5.1.13.2.1\n" expect "enterprises.4779.1.3.5.5.1.13.2.1: (0|1),(0|1),(0|1),(0|1),(0|1),(0|1),(0|1),(0|1)\n" setplugstate "1" $1 off="0" on="1" setplugstate "2" $2 off="0" on="1" setplugstate "3" $3 off="0" on="1" setplugstate "4" $4 off="0" on="1" setplugstate "5" $5 off="0" on="1" setplugstate "6" $6 off="0" on="1" setplugstate "7" $7 off="0" on="1" setplugstate "8" $8 off="0" on="1" expect "snmppower> " } script on { send "set enterprises.4779.1.3.5.3.1.3.1.%s i 1\n" expect "enterprises.4779.1.3.5.3.1.3.1.[1-8]: 1\n" expect "snmppower> " } script off { send "set enterprises.4779.1.3.5.3.1.3.1.%s i 0\n" expect "enterprises.4779.1.3.5.3.1.3.1.[1-8]: 0\n" expect "snmppower> " } script cycle { send "set enterprises.4779.1.3.5.3.1.3.1.%s i 0\n" expect "enterprises.4779.1.3.5.3.1.3.1.[1-8]: 0\n" expect "snmppower> " delay 5 send "set enterprises.4779.1.3.5.3.1.3.1.%s i 1\n" expect "enterprises.4779.1.3.5.3.1.3.1.[1-8]: 1\n" expect "snmppower> " } } powerman-2.4.4/etc/devices/baytech.dev000066400000000000000000000031041467035776500177070ustar00rootroot00000000000000# # $Id$ # # Baytech RPC-3 - old style model (not "NC") # # Tested the following firmware versions: # Revision F 5.00, (C) 2001 # Revision F 5.01, (C) 2001 # Assumes: # 1. command confirmation : disabled (3/configuration, 6/outlets, 2/...) # 2. admin account password : "baytech" (2/manage users, 2/admin, 1/...) # 3. net: prompt for password : enabled (3/configuration, 5/access, 2/...) # Note: prompt is not returned until device is ready to accept another command # specification "baytech" { timeout 10 # about 5 sec for cycle command pingperiod 90 plug name { "1" "2" "3" "4" "5" "6" "7" "8" } script ping { send "\r\n" expect ">" } script login { expect "\n" expect "Enter password>" send "baytech\r\n" expect "Enter Selection>" send "1\r\n" expect ">" } script logout { send "menu\r\n" expect "Enter Selection>" send "6\r\n" } script status_all { send "status\r\n" expect "Circuit Breaker:[^\n]*\r\n" foreachplug { expect "([0-9]+)[ ]+(On|Off)" setplugstate $1 $2 on="On" off="Off" } expect ">" } script on { send "on %s\r\n" expect ">" } script on_all { send "on 0\r\n" expect ">" } script off { send "off %s\r\n" expect ">" } script off_all { send "off 0\r\n" expect ">" } # If outlet is initially off, "reboot" will leave it off. # This doesn't match PowerMan's semantics for cycle, so explicitly power # off then on. script cycle { send "off %s\r\n" expect ">" delay 4 send "on %s\r\n" expect ">" } script cycle_all { send "off 0\r\n" expect ">" delay 4 send "on 0\r\n" expect ">" } } powerman-2.4.4/etc/devices/cb-7050.dev000066400000000000000000000074371467035776500172620ustar00rootroot00000000000000# # Measurement Computing Corp. CB-7050 digital I/O module # # This is "laboratory quality" power control as it requires wires # connected directly to motherboards and some hand tuning of delay values. # # Ref: CB-7000 DIO User's Manual # # Notes: # - Important note: CB-7050 data lines are not isolated and share a common # ground. Beware of ground loops! # - Wire DI[0-6] to +5V side of reset header # - Wire D0[0-7] (open collector) to +5 side of power switch header. # - Wire the CB-7050 ground to moboard ground (send to reset/power headers). # - CB-7050 is presumed to be at address 01 # - CB-7520 RS-232 to RS-485 converter connects to Cyclades TS at 115000 baud. # - DO lines are "open" (0) at power on. Writing 1 connects the line to gnd. # - DI7 is n.c. on the CB-7050. Although plug 7 can be controlled via D07, # power state will always be "unknown" and on/off are effectively toggles. # - [HDAMA] power on delay = 2s, power off delay = 5s. Tune for your moboard. # - This would be cleaner if we could call status_all from off|on scripts. # - This would be cleaner if we had "whileon|whileoff" (no hard coded delays). # specification "cb7050" { timeout 10.0 plug name { "0" "1" "2" "3" "4" "5" "6" "7" } script login { send "$01M\r" # verify module name expect "!017050\r" # model 7050 send "$012\r" # verify conf (type,baud,dfmt) expect "!0140..00\r" # type=40 baud=?? dfmt=00 } script status_all { send "$016\r" # read digital I/O status expect "!..(.)(.)00\r" # $1=DI[4-7] $2=DI[0-3] setplugstate "0" $2 on="1|3|5|7|9|B|D|F" off="0|2|4|6|8|A|C|E" setplugstate "1" $2 on="2|3|6|7|A|B|E|F" off="0|1|4|5|8|9|C|D" setplugstate "2" $2 on="4|5|6|7|C|D|E|F" off="0|1|2|3|8|9|A|B" setplugstate "3" $2 on="8|9|A|B|C|D|E|F" off="0|1|2|3|4|5|6|7" setplugstate "4" $1 on="1|3|5|7|9|B|D|F" off="0|2|4|6|8|A|C|E" setplugstate "5" $1 on="2|3|6|7|A|B|E|F" off="0|1|4|5|8|9|C|D" setplugstate "6" $1 on="4|5|6|7|C|D|E|F" off="0|1|2|3|8|9|A|B" setplugstate "7" $1 # set to unknown } script on { send "$016\r" expect "!..(.)(.)00\r" setplugstate "0" $2 on="1|3|5|7|9|B|D|F" off="0|2|4|6|8|A|C|E" setplugstate "1" $2 on="2|3|6|7|A|B|E|F" off="0|1|4|5|8|9|C|D" setplugstate "2" $2 on="4|5|6|7|C|D|E|F" off="0|1|2|3|8|9|A|B" setplugstate "3" $2 on="8|9|A|B|C|D|E|F" off="0|1|2|3|4|5|6|7" setplugstate "4" $1 on="1|3|5|7|9|B|D|F" off="0|2|4|6|8|A|C|E" setplugstate "5" $1 on="2|3|6|7|A|B|E|F" off="0|1|4|5|8|9|C|D" setplugstate "6" $1 on="4|5|6|7|C|D|E|F" off="0|1|2|3|8|9|A|B" setplugstate "7" $1 off="." # set to off ifoff { send "#01A%s01\r" # 0xA0 | bitnum (set) expect ">\r" delay 4 # XXX: tune me for moboard! send "#01A%s00\r" # 0xA0 | bitnum (clear) expect ">\r" } } script off { send "$016\r" expect "!..(.)(.)00\r" setplugstate "0" $2 on="1|3|5|7|9|B|D|F" off="0|2|4|6|8|A|C|E" setplugstate "1" $2 on="2|3|6|7|A|B|E|F" off="0|1|4|5|8|9|C|D" setplugstate "2" $2 on="4|5|6|7|C|D|E|F" off="0|1|2|3|8|9|A|B" setplugstate "3" $2 on="8|9|A|B|C|D|E|F" off="0|1|2|3|4|5|6|7" setplugstate "4" $1 on="1|3|5|7|9|B|D|F" off="0|2|4|6|8|A|C|E" setplugstate "5" $1 on="2|3|6|7|A|B|E|F" off="0|1|4|5|8|9|C|D" setplugstate "6" $1 on="4|5|6|7|C|D|E|F" off="0|1|2|3|8|9|A|B" setplugstate "7" $1 on="." # set to on ifon { send "#01A%s01\r" # 0xA0 | bitnum (set) expect ">\r" delay 5 # XXX tune me for moboard! send "#01A%s00\r" # 0xA0 | bitnum (clear) expect ">\r" } } # XXX Evil hack - short init* to ground on the module and run pm -f to set # baud rate to 115000 (0A). If beacon isn't shorted, this will just time out. # Power cycle the module after the change. script beacon_on { send "%%0101400A00\r" expect "!01\r" } # # TODO: add support for a CB-7018P at address 02 wired to eight # thermocouples for status_temp support? # } powerman-2.4.4/etc/devices/cyclades-pm10.dev000066400000000000000000000030151467035776500206330ustar00rootroot00000000000000# # Cyclades PM10 # specification "pm10" { timeout 10 pingperiod 60 plug name { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" } script login { expect "Username: " send "admin\n" expect "Password: " send "pm8\n" expect "pm>" } script ping { send "\n" expect "pm>" } script status_all { send "status 1-10\n" expect "Users" foreachplug { expect "([0-9]+)[[:space:]]+Unlocked (ON|OFF)" setplugstate $1 $2 on="ON" off="OFF" } expect "pm>" } script on { send "on %s\n" expect "Outlet turned on." expect "pm>" } script on_all { send "on 1-10\n" foreachplug { expect "Outlet turned on." } expect "pm>" } script off { send "off %s\n" expect "Outlet turned off." expect "pm>" } script off_all { send "off 1-10\n" foreachplug { expect "Outlet turned off." } expect "pm>" } script cycle { send "off %s\n" expect "Outlet turned off." expect "pm>" delay 4 send "on %s\n" expect "Outlet turned on." expect "pm>" } script cycle_all { send "off 1-10\n" foreachplug { expect "Outlet turned off." } expect "pm>" delay 4 send "on 1-10\n" foreachplug { expect "Outlet turned on." } expect "pm>" } script status_temp_all { send "temperature\n" expect "IPDU #1: Temperature: ([0-9.]+)" setplugstate "1" $1 setplugstate "2" $1 setplugstate "3" $1 setplugstate "4" $1 setplugstate "5" $1 setplugstate "6" $1 setplugstate "7" $1 setplugstate "8" $1 setplugstate "9" $1 setplugstate "10" $1 } } powerman-2.4.4/etc/devices/cyclades-pm20.dev000066400000000000000000000034461467035776500206440ustar00rootroot00000000000000# # Cyclades PM20 # specification "pm20" { timeout 25 pingperiod 60 plug name { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "20" } script login { expect "Username: " send "admin\n" expect "Password: " send "pm8\n" expect "pm>" } script ping { send "\n" expect "pm>" } script status_all { send "status 1-20\n" expect "Users" foreachplug { expect "([0-9]+)[[:space:]]+Unlocked (ON|OFF)" setplugstate $1 $2 on="ON" off="OFF" } expect "pm>" } script on { send "on %s\n" expect "Outlet turned on." expect "pm>" } script on_all { send "on 1-20\n" foreachplug { expect "Outlet turned on." } expect "pm>" } script off { send "off %s\n" expect "Outlet turned off." expect "pm>" } script off_all { send "off 1-20\n" foreachplug { expect "Outlet turned off." } expect "pm>" } script cycle { send "off %s\n" expect "Outlet turned off." expect "pm>" delay 4 send "on %s\n" expect "Outlet turned on." expect "pm>" } script cycle_all { send "off 1-20\n" foreachplug { expect "Outlet turned off." } expect "pm>" delay 4 send "on 1-20\n" foreachplug { expect "Outlet turned on." } expect "pm>" } script status_temp_all { send "temperature\n" expect "IPDU #1: Temperature: ([0-9.]+)" setplugstate "1" $1 setplugstate "2" $1 setplugstate "3" $1 setplugstate "4" $1 setplugstate "5" $1 setplugstate "6" $1 setplugstate "7" $1 setplugstate "8" $1 setplugstate "9" $1 setplugstate "10" $1 setplugstate "11" $1 setplugstate "12" $1 setplugstate "13" $1 setplugstate "14" $1 setplugstate "15" $1 setplugstate "16" $1 setplugstate "17" $1 setplugstate "18" $1 setplugstate "19" $1 setplugstate "20" $1 } } powerman-2.4.4/etc/devices/cyclades-pm42.dev000066400000000000000000000027171467035776500206500ustar00rootroot00000000000000# # Cyclades PM42 # specification "pm42" { timeout 10 pingperiod 60 plug name { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "20" "21" "22" "23" "24" "25" "26" "27" "28" "29" "30" "31" "32" "33" "34" "35" "36" "37" "38" "39" "40" "41" "42" } script login { expect "Username: " send "admin\n" expect "Password: " send "pm8\n" expect "pm>" } script ping { send "\n" expect "pm>" } script status_all { send "status 1-42\n" expect "Users" foreachplug { expect "([0-9]+)[[:space:]]+Unlocked (ON|OFF)" setplugstate $1 $2 on="ON" off="OFF" } expect "pm>" } script on { send "on %s\n" expect "Outlet turned on." expect "pm>" } script on_all { send "on 1-42\n" foreachplug { expect "Outlet turned on." } expect "pm>" } script off { send "off %s\n" expect "Outlet turned off." expect "pm>" } script off_all { send "off 1-42\n" foreachplug { expect "Outlet turned off." } expect "pm>" } script cycle { send "off %s\n" expect "Outlet turned off." expect "pm>" delay 4 send "on %s\n" expect "Outlet turned on." expect "pm>" } script cycle_all { send "off 1-42\n" foreachplug { expect "Outlet turned off." } expect "pm>" delay 4 send "on 1-42\n" foreachplug { expect "Outlet turned on." } expect "pm>" } } powerman-2.4.4/etc/devices/cyclades-pm8.dev000066400000000000000000000027501467035776500205670ustar00rootroot00000000000000# # Cyclades PM8/PM8i s/w v. 1.0.9a # specification "pm8" { timeout 10 pingperiod 60 plug name { "1" "2" "3" "4" "5" "6" "7" "8" } script login { expect "Username: " send "admin\n" expect "Password: " send "pm8\n" expect "pm>" } script ping { send "\n" expect "pm>" } script status_all { send "status 1-8\n" expect "Users" foreachplug { expect "([0-9]+)[[:space:]]+Unlocked (ON|OFF)" setplugstate $1 $2 on="ON" off="OFF" } expect "pm>" } script on { send "on %s\n" expect "Outlet turned on." expect "pm>" } script on_all { send "on 1-8\n" foreachplug { expect "Outlet turned on." } expect "pm>" } script off { send "off %s\n" expect "Outlet turned off." expect "pm>" } script off_all { send "off 1-8\n" foreachplug { expect "Outlet turned off." } expect "pm>" } script cycle { send "off %s\n" expect "Outlet turned off." expect "pm>" delay 4 send "on %s\n" expect "Outlet turned on." expect "pm>" } script cycle_all { send "off 1-8\n" foreachplug { expect "Outlet turned off." } expect "pm>" delay 4 send "on 1-8\n" foreachplug { expect "Outlet turned on." } expect "pm>" } script status_temp_all { send "temperature\n" expect "IPDU #1: Temperature: ([0-9.]+)" setplugstate "1" $1 setplugstate "2" $1 setplugstate "3" $1 setplugstate "4" $1 setplugstate "5" $1 setplugstate "6" $1 setplugstate "7" $1 setplugstate "8" $1 } } powerman-2.4.4/etc/devices/dli.dev000066400000000000000000000023411467035776500170420ustar00rootroot00000000000000# Support for 8-port Digital Loggers, Inc. models: # # www.digital-loggers.com/lpc.html # www.digital-loggers.com/epcr2.html # www.digital-loggers.com/din.html # # Powerman.conf should look something like this: # include "/etc/powerman/dli.dev" # device "lpc" "dli" "/usr/sbin/httppower -u http://192.168.0.100 |&" # node "p[1-8]" "lpc" "[1-8]" # specification "dli" { timeout 30 plug name { "1" "2" "3" "4" "5" "6" "7" "8" } script login { expect "httppower> " send "auth admin:admin\n" expect "httppower> " } script logout { send "quit\n" } script status_all { send "get\n" expect "Controller:" foreachplug { expect "Outlet ([1-8]+)[^O]*(ON|OFF)" setplugstate $1 $2 on="ON" off="OFF" } expect "httppower> " } script on { send "post outlet %s=ON\n" expect "httppower> " } script off { send "post outlet %s=OFF\n" expect "httppower> " } script cycle { send "post outlet %s=OFF\n" expect "httppower> " delay 4 send "post outlet %s=ON\n" expect "httppower> " } script cycle_all { foreachplug { send "post outlet %s=OFF\n" expect "httppower> " } delay 4 foreachplug { send "post outlet %s=ON\n" expect "httppower> " } } } powerman-2.4.4/etc/devices/dli4.dev000066400000000000000000000023241467035776500171270ustar00rootroot00000000000000# Support for 8-port Digital Loggers, Inc. web power switch III or IV # # Powerman.conf should look something like this: # include "/etc/powerman/dli4.dev" # device "lpc" "dli4" "/usr/sbin/httppower -u http://192.168.0.100 |&" # node "p[1-8]" "lpc" "[1-8]" # # Thanks to Gaylord Holder for providing info to create this script. # specification "dli4" { timeout 30 plug name { "1" "2" "3" "4" "5" "6" "7" "8" } script login { expect "httppower> " send "auth admin:1234\n" expect "httppower> " } script logout { send "quit\n" } script status_all { send "get index.htm\n" expect "Controller:" foreachplug { expect "Outlet ([1-8]+)[^O]*(ON|OFF)" setplugstate $1 $2 on="ON" off="OFF" } expect "httppower> " } script on { send "post outlet %s=ON\n" expect "httppower> " } script off { send "post outlet %s=OFF\n" expect "httppower> " } script cycle { send "post outlet %s=OFF\n" expect "httppower> " delay 4 send "post outlet %s=ON\n" expect "httppower> " } script cycle_all { foreachplug { send "post outlet %s=OFF\n" expect "httppower> " } delay 4 foreachplug { send "post outlet %s=ON\n" expect "httppower> " } } } powerman-2.4.4/etc/devices/eaton-epdu-blue-switched.dev000066400000000000000000000045271467035776500231000ustar00rootroot00000000000000# eaton-epdu-blue-switched.dev # Eaton Vertical Mount (0U) Switched ePDUs with Blue and Yellow Local Display # Contributed by Paul Anderson (panderson@sgi.com) # # Example powerman.conf device line: # device "epdu1" "eaton-epdu-blue-switched" "/usr/sbin/snmppower -h epdu1|&" # # N.B. This script requires that you download and install the Eaton ePDU MIB # where net-snmp can find it, e.g.: # /usr/share/snmp/mibs/Pulizzi-Vertical-SW-ePDU.txt # # Download ePDU_MIB_Switched_Blue_Display.zip from: # powerquality.eaton.com/Support/Software-Drivers/Downloads/ePDU-firmware.asp # specification "eaton-epdu-blue-switched" { timeout 10 plug name { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "20" "21" "22" "23" "24" } script login { expect "snmppower> " send "start_v2c private\n" expect "snmppower> " send "mib Pulizzi\n" expect "snmppower> " } script logout { send "finish\n" expect "snmppower> " } script status { send "get Pulizzi::outlet%sStatus.0\n" expect "Pulizzi::outlet([0-9]+)Status.0: (1|2)\n" setplugstate $1 $2 on="1" off="2" expect "snmppower> " } script on { send "set Pulizzi::outlet%sCommand.0 i 1\n" expect "Pulizzi::outlet[0-9]+Command.0: 1\n" expect "snmppower> " delay 0.3 } script off { send "set Pulizzi::outlet%sCommand.0 i 2\n" expect "Pulizzi::outlet[0-9]+Command.0: 2\n" expect "snmppower> " } script reset { send "set Pulizzi::outlet%sCommand.0 i 3\n" expect "Pulizzi::outlet[0-9]+Command.0: 3\n" expect "snmppower> " delay 0.3 } script cycle { send "set Pulizzi::outlet%sCommand.0 i 2\n" expect "Pulizzi::outlet[0-9]+Command.0: 2\n" expect "snmppower> " delay 5 send "set Pulizzi::outlet%sCommand.0 i 1\n" expect "Pulizzi::outlet[0-9]+Command.0: 1\n" expect "snmppower> " delay 0.3 } } powerman-2.4.4/etc/devices/eaton-revelation-snmp.dev000066400000000000000000000025321467035776500225230ustar00rootroot00000000000000# Eaton PowerWare model PW102MA0U025 via SNMP # Example powerman.conf device line: # device "epdu1" "eaton-revelation-snmp" "/usr/sbin/snmppower -h epdu1|&" specification "eaton-revelation-snmp" { timeout 10 plug name { "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" } script login { expect "snmppower> " send "start_v2c private\n" expect "snmppower> " } script logout { send "finish\n" expect "snmppower> " } script status { send "get enterprises.534.6.6.6.1.2.2.1.3.%s\n" expect "enterprises.534.6.6.6.1.2.2.1.3.([0-9]+): (0|1)" setplugstate $1 $2 on="1" off="0" expect "snmppower> " } script on { send "set enterprises.534.6.6.6.1.2.2.1.3.%s i 1\n" expect "enterprises.534.6.6.6.1.2.2.1.3.[0-9]+: 1\n" expect "snmppower> " delay 0.3 } script off { send "set enterprises.534.6.6.6.1.2.2.1.3.%s i 0\n" expect "enterprises.534.6.6.6.1.2.2.1.3.[0-9]+: 0\n" expect "snmppower> " } script cycle { send "set enterprises.534.6.6.6.1.2.2.1.3.%s i 0\n" expect "enterprises.534.6.6.6.1.2.2.1.3.[0-9]+: 0\n" expect "snmppower> " delay 5 send "set enterprises.534.6.6.6.1.2.2.1.3.%s i 1\n" expect "enterprises.534.6.6.6.1.2.2.1.3.[0-9]+: 1\n" expect "snmppower> " delay 0.3 } } powerman-2.4.4/etc/devices/hp3488.dev000066400000000000000000000013711467035776500172320ustar00rootroot00000000000000# # HP3488 switch/control unit using 'hp3488' utility from gpib-utils project. # # device "hp0" "hp3488" "/usr/bin/hp3488 --shell|&" # # "Plug" names for this device are three digit values consisting of # a single digit slot number (1-5) followed by two digit channel number. # specification "hp3488" { timeout 5 script login { expect "hp3488> " } script logout { send "quit\n" } script status { send "query %s\n" expect "([1-5][0-9]{2}): ([01])\n" setplugstate $1 $2 off="0" on="1" expect "hp3488> " } script on_ranged { send "on %s\n" expect "hp3488> " } script off_ranged { send "off %s\n" expect "hp3488> " } script cycle_ranged { send "off %s\n" expect "hp3488> " delay 4 send "on %s\n" expect "hp3488> " } } powerman-2.4.4/etc/devices/hpilo.dev000066400000000000000000000024741467035776500174140ustar00rootroot00000000000000# HP Integrated Lights-Out management device (iLO) # # (c) Copyright 2009 Hewlett-Packard Development Company, L.P. # Bjorn Helgaas # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # Example: # device "dl360-001" "hpilo" "dl360-001-ilo.test:23" # node "dl360-001" "dl360-001" # # Tested on: # DL360 (iLO firmware 1.93) # DL320 (iLO firmware 1.42) # BL465c G5 (iLO firmware 1.61) specification "hpilo" { timeout 10 plug name { "1" } script login { expect "Login Name: " send "Admin\r\n" expect "Password: " send "Admin\r\n" expect "hpiLO-> " } script status { send "power\r\n" expect "server power is currently: (On|Off)" setplugstate "1" $1 on="On" off="Off" expect "hpiLO-> " } script on { send "power on\r\n" expect "hpiLO-> " } script off { send "power off\r\n" expect "hpiLO-> " } script reset { send "reset system1\r\n" expect "hpiLO-> " } script status_beacon { send "uid\r\n" expect "The UID light is currently: (On|Off)" setplugstate "1" $1 on="On" off="Off" expect "hpiLO-> " } script beacon_on { send "uid on\r\n" expect "hpiLO-> " } script beacon_off { send "uid off\r\n" expect "hpiLO-> " } } powerman-2.4.4/etc/devices/hpmp.dev000066400000000000000000000025651467035776500172460ustar00rootroot00000000000000# HP Management Processor device (MP) # a.k.a. Integrated Lights-Out HP Integrity # # (c) Copyright 2009 Hewlett-Packard Development Company, L.P. # Bjorn Helgaas # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # Example: # device "rx3600-001" "hpmp" "rx3600-001-mp.test:23" # node "rx3600-001" "rx3600-001" # # Tested on: # rx3600 (MP firmware F.01.41) # rx1600 (MP firmware E.03.30) # rx1620 (MP firmware E.03.30) specification "hpmp" { timeout 10 plug name { "1" } script login { expect "MP login: " send "Admin\r\n" expect "MP password: " send "Admin\r\n" expect "MP> " send "cm\r\n" expect "MP:CM> " } script status { send "ps\r\n" expect "System Power state[^O]+(On|Off)" setplugstate "1" $1 on="On" off="Off" expect "MP:CM> " } script on { send "pc -on -nc\r\n" expect "MP:CM> " } script off { send "pc -off -nc\r\n" expect "MP:CM> " } script reset { send "rs -nc\r\n" expect "MP:CM> " } script status_beacon { send "loc -nc\r\n" expect "Current -> Locator LED (On|Off)" setplugstate "1" $1 on="On" off="Off" expect "MP:CM> " } script beacon_on { send "loc -on -nc\r\n" expect "MP:CM> " } script beacon_off { send "loc -off -nc\r\n" expect "MP:CM> " } } powerman-2.4.4/etc/devices/hpmpblade.dev000066400000000000000000000024761467035776500202370ustar00rootroot00000000000000# HP Management Processor device (MP) # a.k.a. Integrity Integrated Lights-Out 2 # # (c) Copyright 2009 Hewlett-Packard Development Company, L.P. # Bjorn Helgaas # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # Example: # device "bl860c-001" "hpmpblade" "bl860c-001-mp.test:23" # node "bl860c-001" "bl860c-001" # # Tested on: # BL860c (MP firmware T.02.16) specification "hpmpblade" { timeout 10 plug name { "1" } script login { expect "login: " send "Admin\r\n" expect "password: " send "Admin\r\n" expect "MP> " send "cm\r\n" expect "MP:CM> " } script status { send "ps\r\n" expect "System Power state[^O]+(On|Off)" setplugstate "1" $1 on="On" off="Off" expect "MP:CM> " } script on { send "pc -on -nc\r\n" expect "MP:CM> " } script off { send "pc -off -nc\r\n" expect "MP:CM> " } script reset { send "rs -nc\r\n" expect "MP:CM> " } script status_beacon { send "loc -nc\r\n" expect "Server Locator UID LED[^O]+(On|Off)" setplugstate "1" $1 on="On" off="Off" expect "MP:CM> " } script beacon_on { send "loc -on -nc\r\n" expect "MP:CM> " } script beacon_off { send "loc -off -nc\r\n" expect "MP:CM> " } } powerman-2.4.4/etc/devices/hpmpcell.dev000066400000000000000000000041001467035776500200710ustar00rootroot00000000000000# HP Management Processor device (MP) for mid-range cellular systems # # (c) Copyright 2009 Hewlett-Packard Development Company, L.P. # Bjorn Helgaas # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # Example: # device "rx8620-001" "hpmpcell" "rx8620-001-mp.test:23" # node "rx8620-001-p0" "rx8620-001" "0" # # Tested on: # rx8620 (MP firmware A.7.008, A.8.005) # # This handles each partition separately. The "plug" argument to node is the # partition number. # # N.B. This only works on mid-range, e.g., rx7620, rx7640, rx8620, and rx8640. # It doesn't handle Superdome because Superdome uses "P" to select partition, # not "R". It should support PA-RISC systems, e.g., rp7620, rp7640, etc. specification "hpmpcell" { timeout 10 script login { expect "MP login: " send "Admin\r\n" expect "MP password: " send "Admin\r\n" expect "MP> " send "cm\r\n" expect "MP:CM> " } script status { send "pe\r\n" expect "Select Device: " send "r\r\n" expect "Select a partition number: " send "%s\r\n" expect "The power state is (ON|OFF)" setplugstate $1 on="ON" off="OFF" expect "In what state do you want the power.*\? " send "q\r\n" expect "MP:CM> " } script on { send "pe\r\n" expect "Select Device: " send "r\r\n" expect "Select a partition number: " send "%s\r\n" expect "The power state is (ON|OFF)" setplugstate $1 on="ON" off="OFF" expect "In what state do you want the power.*\? " send "on\r\n" expect "MP:CM> " } script off { send "pe\r\n" expect "Select Device: " send "r\r\n" expect "Select a partition number: " send "%s\r\n" expect "The power state is (ON|OFF)" setplugstate $1 on="ON" off="OFF" expect "In what state do you want the power.*\? " send "off\r\n" expect "MP:CM> " } script reset { send "rs\r\n" expect "Select a partition number: " send "%s\r\n" expect "Do you want to reset partition number.*\? " send "y\r\n" expect "MP:CM> " } } powerman-2.4.4/etc/devices/hpmpdome.dev000066400000000000000000000036031467035776500201050ustar00rootroot00000000000000# HP Management Processor device (MP) for high-end cellular systems # # (c) Copyright 2009 Hewlett-Packard Development Company, L.P. # Bjorn Helgaas # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # Example: # device "sd-001" "hpmpdome" "sd-001-mp.test:23" # node "sd-001-p0" "sd-001" "0" # # Tested on: # SD64B (MP firmware 26.5.1) # # This handles each partition separately. The "plug" argument to node is the # partition number. # # N.B. This only works on Superdomes, not mid-range cellular systems. specification "hpmpdome" { timeout 10 script login { expect "MP login: " send "Admin\r\n" expect "MP password: " send "Admin\r\n" expect "MP> " send "cm\r\n" expect "MP:CM> " } script status { send "pe\r\n" expect "Select Device: " send "p\r\n" expect "Select a partition number: " send "%s\r\n" expect "The power state is (ON|OFF)" setplugstate $1 on="ON" off="OFF" expect "In what state do you want the power.*\? " send "q\r\n" expect "MP:CM> " } script on { send "pe\r\n" expect "Select Device: " send "p\r\n" expect "Select a partition number: " send "%s\r\n" expect "The power state is (ON|OFF)" setplugstate $1 on="ON" off="OFF" expect "In what state do you want the power.*\? " send "on\r\n" expect "MP:CM> " } script off { send "pe\r\n" expect "Select Device: " send "p\r\n" expect "Select a partition number: " send "%s\r\n" expect "The power state is (ON|OFF)" setplugstate $1 on="ON" off="OFF" expect "In what state do you want the power.*\? " send "off\r\n" expect "MP:CM> " } script reset { send "rs\r\n" expect "Select a partition number: " send "%s\r\n" expect "Do you want to reset partition number.*\? " send "y\r\n" expect "MP:CM> " } } powerman-2.4.4/etc/devices/ibmbladecenter.dev000066400000000000000000000022001467035776500212240ustar00rootroot00000000000000# # Originally ibmbladecenter.dev. RJG, 11/17/04 # # Ref: Command-Line Interface Reference Guide for # IBM BladeCenter Management Module, BladeCenter T Management Module, # Advanced Management Module, BladeCenter T Advanced Management Module. # specification "ibmbladecenter" { timeout 15 plug name { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" } script login { expect "username: " send "USERID\r\n" expect "password: " send "PASSW0RD\r\n" expect "system> " send "telnetcfg -t 0 -T mm[1]\r\n" expect "OK\r\nsystem> " } script logout { send "exit\r\n" } script status { send "power -state -T blade\[%s\]\r\n" expect "(On|Off)\r\nsystem> " setplugstate $1 on="On" off="Off" } script on { send "power -on -T blade\[%s\]\r\n" delay 1 # settling time expect "OK\r\nsystem> " } script off { send "power -off -T blade\[%s\]\r\n" delay 5 # settling time expect "OK\r\nsystem> " } script cycle { send "power -off -T blade\[%s\]\r\n" expect "OK\r\nsystem> " delay 5 # settling time delay 4 send "power -on -T blade\[%s\]\r\n" expect "OK\r\nsystem> " } } powerman-2.4.4/etc/devices/icebox.dev000066400000000000000000000036471467035776500175550ustar00rootroot00000000000000# # $Id$ # # Linux Networx ICE box firmware version 2.x on port 1010. # specification "icebox" { timeout 20 # accommodate 14 sec plus "cycle *" time */ plug name { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" } script login { expect "V2[^\n]*\r\n" send "auth icebox\r\n" expect "OK\r\n" } script logout { send "q\r\n" } script status_all { send "ps *\r\n" expect "N1:([01]) N2:([01]) N3:([01]) N4:([01]) N5:([01]) N6:([01]) N7:([01]) N8:([01]) N9:([01]) N10:([01])[[:space:]]*\r\n" setplugstate "1" $1 off="0" on="1" setplugstate "2" $2 off="0" on="1" setplugstate "3" $3 off="0" on="1" setplugstate "4" $4 off="0" on="1" setplugstate "5" $5 off="0" on="1" setplugstate "6" $6 off="0" on="1" setplugstate "7" $7 off="0" on="1" setplugstate "8" $8 off="0" on="1" setplugstate "9" $9 off="0" on="1" setplugstate "10" $10 off="0" on="1" } script status_temp_all { send "ts *\r\n" expect "N1:([0-9,]+) N2:([0-9,]+) N3:([0-9,]+) N4:([0-9,]+) N5:([0-9,]+) N6:([0-9,]+) N7:([0-9,]+) N8:([0-9,]+) N9:([0-9,]+) N10:([0-9,]+) N11:[0-9,]+ N12:[0-9,]+[[:space:]]*\r\n" setplugstate "1" $1 setplugstate "2" $2 setplugstate "3" $3 setplugstate "4" $4 setplugstate "5" $5 setplugstate "6" $6 setplugstate "7" $7 setplugstate "8" $8 setplugstate "9" $9 setplugstate "10" $10 } script on { send "ph %s\r\n" expect "OK\r\n" delay 0.7 } script on_all { send "ph *\r\n" expect "OK\r\n" delay 7 } script off { send "pl %s\r\n" expect "OK\r\n" delay 0.7 } script off_all { send "pl *\r\n" expect "OK\r\n" delay 7 } script cycle { send "pl %s\r\n" expect "OK\r\n" delay 4 send "ph %s\r\n" expect "OK\r\n" delay 0.7 } script cycle_all { send "pl *\r\n" expect "OK\r\n" delay 9 send "ph *\r\n" expect "OK\r\n" delay 7 } script reset { send "rp %s\r\n" expect "OK\r\n" delay 0.7 } script reset_all { send "rp *\r\n" expect "OK\r\n" delay 7 } } powerman-2.4.4/etc/devices/icebox3.dev000066400000000000000000000061511467035776500176310ustar00rootroot00000000000000# # $Id$ # # Linux Networx ICE Box firmware version 3.x and 4.x on port 1010. # # For 3.0 B70 or better, 2 sec delays in beacon_on/beacon_off can be # commented out. # specification "icebox3" { timeout 20 plug name { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" } script login { expect "V[34][^\n]*\r\n" send "auth icebox\r\n" expect "OK\r\n" } script logout { send "q\r\n" } script status_all { send "ps *\r\n" expect "N1:([01]) N2:([01]) N3:([01]) N4:([01]) N5:([01]) N6:([01]) N7:([01]) N8:([01]) N9:([01]) N10:([01])[[:space:]]*\r\n" setplugstate "1" $1 off="0" on="1" setplugstate "2" $2 off="0" on="1" setplugstate "3" $3 off="0" on="1" setplugstate "4" $4 off="0" on="1" setplugstate "5" $5 off="0" on="1" setplugstate "6" $6 off="0" on="1" setplugstate "7" $7 off="0" on="1" setplugstate "8" $8 off="0" on="1" setplugstate "9" $9 off="0" on="1" setplugstate "10" $10 off="0" on="1" } # Assumption: v3 implies that "ts" is deprecated in favor of "is" script status_temp_all { send "is *\r\n" expect "N1:([^ ]+) N2:([^ ]+) N3:([^ ]+) N4:([^ ]+) N5:([^ ]+) N6:([^ ]+) N7:([^ ]+) N8:([^ ]+) N9:([^ ]+) N10:([^ ]+) N11:[^ ]+ N12:[^ ]+[[:space:]]*\r\n" setplugstate "1" $1 setplugstate "2" $2 setplugstate "3" $3 setplugstate "4" $4 setplugstate "5" $5 setplugstate "6" $6 setplugstate "7" $7 setplugstate "8" $8 setplugstate "9" $9 setplugstate "10" $10 } script status_beacon_all { send "be *\r\n" expect "N1:([A-Z]+) N2:([A-Z]+) N3:([A-Z]+) N4:([A-Z]+) N5:([A-Z]+) N6:([A-Z]+) N7:([A-Z]+) N8:([A-Z]+) N9:([A-Z]+) N10:([A-Z]+) N11:[A-Z]+ N12:[A-Z]+[[:space:]]*\r\n" setplugstate "1" $1 off="OFF" on="ON" setplugstate "2" $2 off="OFF" on="ON" setplugstate "3" $3 off="OFF" on="ON" setplugstate "4" $4 off="OFF" on="ON" setplugstate "5" $5 off="OFF" on="ON" setplugstate "6" $6 off="OFF" on="ON" setplugstate "7" $7 off="OFF" on="ON" setplugstate "8" $8 off="OFF" on="ON" setplugstate "9" $9 off="OFF" on="ON" setplugstate "10" $10 off="OFF" on="ON" } script on { send "ph %s\r\n" expect "OK\r\n" delay 0.7 } script on_all { send "ph *\r\n" expect "OK\r\n" delay 7 } script off { send "pl %s\r\n" expect "OK\r\n" delay 0.7 } script off_all { send "pl *\r\n" expect "OK\r\n" delay 7 } script cycle { send "pl %s\r\n" expect "OK\r\n" delay 4 send "ph %s\r\n" expect "OK\r\n" delay 0.7 } script cycle_all { send "pl *\r\n" expect "OK\r\n" delay 9 send "ph *\r\n" expect "OK\r\n" delay 7 } script reset { send "rp %s\r\n" expect "OK\r\n" delay 0.7 } script reset_all { send "rp *\r\n" expect "OK\r\n" delay 7 } script beacon_on { send "be %s on\r\n" expect "OK\r\n" delay 2 } script beacon_off { send "be %s off\r\n" expect "OK\r\n" delay 2 } } powerman-2.4.4/etc/devices/ics8064.dev000066400000000000000000000032411467035776500173720ustar00rootroot00000000000000# # ICS 8064 16-port relay box using 'ics8064' utility from gpib-utils project. # # "/usr/bin/ics8064 --shell|&" # # Remember to run: # ics8064 --comm-timeout=0 # ics8064 --commit-config # specification "ics8064" { timeout 5 plug name { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" "16" } script login { expect "ics8064> " } script logout { send "quit\n" } script status_all { send "status\n" expect "([01]), ([01]), ([01]), ([01]), ([01]), ([01]), ([01]), ([01]), ([01]), ([01]), ([01]), ([01]), ([01]), ([01]), ([01]), ([01])\n" setplugstate "1" $1 off="0" on="1" setplugstate "2" $2 off="0" on="1" setplugstate "3" $3 off="0" on="1" setplugstate "4" $4 off="0" on="1" setplugstate "5" $5 off="0" on="1" setplugstate "6" $6 off="0" on="1" setplugstate "7" $7 off="0" on="1" setplugstate "8" $8 off="0" on="1" setplugstate "9" $9 off="0" on="1" setplugstate "10" $10 off="0" on="1" setplugstate "11" $11 off="0" on="1" setplugstate "12" $12 off="0" on="1" setplugstate "13" $13 off="0" on="1" setplugstate "14" $14 off="0" on="1" setplugstate "15" $15 off="0" on="1" setplugstate "16" $16 off="0" on="1" expect "ics8064> " } script on_ranged { send "close %s\n" expect "ics8064> " } script off_ranged { send "open %s\n" expect "ics8064> " } script cycle_ranged { send "open %s\n" expect "ics8064> " delay 4 send "close %s\n" expect "ics8064> " } } powerman-2.4.4/etc/devices/ilom.dev000066400000000000000000000024741467035776500172410ustar00rootroot00000000000000# # Sun Integrated Lights Out Management card # # Verified on: # Sunfire X4140 SP firmware 2.0.2.3 build 29049, SP file system 0.1.16 # Sunfire X4550 SP firmware 2.0.2.5 build 32394, SP file system 0.1.16 # # Examples: # over SER MGT RJ-45 (serial via cyclades) # device "ilom" "ilom" "usr-ts:7016" # over SER MGT RJ-45 (direct serial) # device "ilom" "ilom" "/dev/ttyS1" "9600,8n1" # over NET MGT RJ-45 (network over ssh) # device "ilom" "ilom" "ssh -o StrictHostKeyChecking=no -lroot sol|&" # specification "ilom" { timeout 10 plug name { "1" } # login script handles three cases: # 1) serial port, already logged in # 2) serial port, not logged in # 3) ssh, enter password only script login { send "\n" expect "->|Password:|login: " send "root\n" expect "->|Password: " send "changeme\n" expect "->" } script status { send "show -d properties /SYS\n" expect "(POWERSTATE|power_state)[^Oo]+(On|Off|on|off)" setplugstate "1" $2 on="On|on" off="Off|off" expect "->" } script on { send "start -script /SYS\n" expect "->" } script off { send "stop -script -force /SYS\n" expect "->" } script cycle { send "stop -script -force /SYS\n" expect "->" delay 4 send "start -script /SYS\n" expect "->" } script reset { send "reset -script /SYS\n" expect "->" } } powerman-2.4.4/etc/devices/ipmi.dev000066400000000000000000000024531467035776500172340ustar00rootroot00000000000000# # $Id$ # # IPMI 1.5 in terminal mode # Tested on Intel SE7501WV2 motherboard over serial. # On this motherboard, the System Setup Utility is used to switch # the BMC into terminal mode. # # References: # "IPMI over Cyclades TS2000", M.P. Anand Babu # "IPMI 1.5 Reference Guide", 13.7.8 Terminal Mode ASCII Text Commands (p.175) # http://www.intel.com/design/servers/ipmi/ # http://www.intel.com/design/servers/ipmi/spec.htm # # specification "ipmi" { timeout 10 plug name { "1" } script login { send "\033(" expect "\\[TMODE OK\\]\r\n" send "[SYS PWD -N]\r" # null password/username expect "\\[OK\\]\r\n" } script logout { send "[SYS PWD -X]\r" } script status { send "[SYS HEALTH QUERY]\r" expect "\\[OK PWR:(ON|OFF|SLP|S4|S3|S2|S1).*\\]\r\n" setplugstate "1" $1 on="ON" off="OFF|SLP|S4|S3|S2|S1" } script on { send "[SYS POWER ON]\r" expect "\\[OK\\]\r\n" } script off { send "[SYS POWER OFF]\r" expect "\\[OK\\]\r\n" } script reset { send "[SYS RESET]\r" expect "\\[OK\\]\r\n" } script cycle { send "[SYS POWER OFF]\r" expect "\\[OK\\]\r\n" delay 4 send "[SYS POWER ON]\r" expect "\\[OK\\]\r\n" } script status_temp { send "[SYS HEALTH QUERY]\r" expect "\\[OK PWR:[^ ]* H:.. T:(ok|nc|cr|nr|uf).*\\]\r\n" setplugstate "1" $1 } } powerman-2.4.4/etc/devices/ipmipower-serial.dev000066400000000000000000000031631467035776500215650ustar00rootroot00000000000000# # $Id$ # # This device configuration supports power control via the # 'ipmipower' utility. # # This device file is identical to the ipmipower.dev device file, # except that power control scripts are not ranged. Therefore, power # control operations are passed to ipmipower serially instead of in a # range. # # This device file may be more useful than ipmipower.dev on networks # that do not scale well and require power control operations to be # sent out more slowly. It may also be useful when ipmipower is # executed with the --oem-power-type option. A number of IPMI power # controllable devices may not be able to handle power control # operations quickly and the operations must be slowed down. # # off,delay,on used in place of IPMI cycle to ensure full command # completion before returning to the user. # specification "ipmipowerserial" { timeout 60 script login { expect "ipmipower> " } script logout { send "quit\n" } script status_all { send "stat\n" foreachnode { expect "([^\n:]+): ([^\n]+)\n" setplugstate $1 $2 on="on" off="off" } expect "ipmipower> " } script status_beacon_all { send "identify-status\n" foreachnode { expect "([^\n:]+): ([^\n]+)\n" setplugstate $1 $2 on="on" off="off" } expect "ipmipower> " } script on { send "on %s\n" expect "ipmipower> " } script off { send "off %s\n" expect "ipmipower> " } script cycle { send "off %s\n" expect "ipmipower> " delay 5 send "on %s\n" expect "ipmipower> " } script beacon_on { send "identify-on %s\n" expect "ipmipower> " } script beacon_off { send "identify-off %s\n" expect "ipmipower> " } } powerman-2.4.4/etc/devices/ipmipower.dev000066400000000000000000000032131467035776500203040ustar00rootroot00000000000000# # $Id$ # # This device configuration supports power control via the FreeIPMI # 'ipmipower' utility. # # Powerman.conf will typically be setup like this: # # include "/etc/powerman/ipmipower.dev" # device "ipmipower1" "ipmipower" "/usr/sbin/ipmipower -h pnode1 --wait-until-on --wait-until-off |&" # node "node1" "ipmipower1" "pnode1" # # It may also be necessary to configure a username and password for # ipmipower. It may be configured on the command line above or # (recommended) via the FreeIPMI configuration file. # # some IPMI devices require some time for the firmware to # reload/re-settle itself after a power-off. A delay of 5 seconds # seems to work fine pretty well. # # off,delay,on used in place of IPMI cycle to ensure full command # completion before returning to the user. # specification "ipmipower" { timeout 60 script login { expect "ipmipower> " } script logout { send "quit\n" } script status_all { send "stat\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setplugstate $1 $2 on="^on\n" off="^off\n" } expect "ipmipower> " } script status_beacon_all { send "identify-status\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setplugstate $1 $2 on="^on\n" off="^off\n" } expect "ipmipower> " } script on_ranged { send "on %s\n" expect "ipmipower> " } script off_ranged { send "off %s\n" expect "ipmipower> " } script cycle_ranged { send "off %s\n" expect "ipmipower> " delay 5 send "on %s\n" expect "ipmipower> " } script beacon_on_ranged { send "identify-on %s\n" expect "ipmipower> " } script beacon_off_ranged { send "identify-off %s\n" expect "ipmipower> " } } powerman-2.4.4/etc/devices/kvm-ssh.dev000066400000000000000000000022161467035776500176630ustar00rootroot00000000000000###KVM (Kernel-based Virtual Machine) over ssh script### # PowerMan script for controlling virtual machines running on remote KVM (Kernel-based Virtual Machine) hypervisors, e.g. # after setting up passwordless ssh access to hypervisor: # device "hypervisor_hostname/IP_address" "kvm-ssh" "/usr/bin/ssh -o StrictHostKeyChecking=no -a -l username -p 22 hypervisor_hostname/IP_address|&" # node "vm_name" "hypervisor_hostname/IP_address" "vm_name" # specification "kvm-ssh" { timeout 5 script login { expect "#" } script logout { send "exit\n" } script status { send "virsh domstate %s\n" expect "(running|off)" setplugstate $1 off="off" on="running" } script on { send "virsh start %s\n" expect "started|Domain is already active" } script off { send "virsh destroy %s\n" expect "destroyed|domain is not running" } script cycle { #yes, there is a reset command, but it does nothing if the vm is powered off send "virsh destroy %s\n" expect "destroyed|domain is not running" delay 1 send "virsh start %s\n" expect "started|Domain is already active" } } powerman-2.4.4/etc/devices/kvm.dev000066400000000000000000000015721467035776500170740ustar00rootroot00000000000000###KVM (Kernel-based Virtual Machine) script### # PowerMan script for controlling virtual machines running on local KVM (Kernel-based Virtual Machine) hypervisors, e.g. # # device "kvm" "kvm" "/usr/bin/virsh |&" # node "vm_name" "kvm" "vm_name" # specification "kvm" { timeout 5 script login { expect "virsh #" } script logout { send "quit\n" } script status { send "domstate %s\n" expect "(running|off)" setplugstate $1 off="off" on="running" } script on { send "start %s\n" expect "started|Domain is already active" } script off { send "destroy %s\n" expect "destroyed|domain is not running" } script cycle { #yes, there is a reset command, but it does nothing if the vm is powered off send "destroy %s\n" expect "destroyed|domain is not running" delay 1 send "start %s\n" expect "started|Domain is already active" } } powerman-2.4.4/etc/devices/lom.dev000066400000000000000000000022551467035776500170650ustar00rootroot00000000000000# # Sun LOM # # Verified on (only via ssh so far): # Sun v40, Version V2.1.0.16 # # Examples: # over SER MGT RJ-45 (serial via cyclades) # device "lom" "lom" "usr-ts:7016" # over SER MGT RJ-45 (direct serial) # device "lom" "lom" "/dev/ttyS1" "9600,8n1" # over NET MGT RJ-45 (network over ssh) # device "lom" "lom" "ssh -o StrictHostKeyChecking=no -ladmin sol|&" # specification "lom" { timeout 10 plug name { "1" } # login script handles three cases: # 1) serial port, already logged in # 2) serial port, not logged in # 3) ssh, enter password only script login { send "\n" expect "\\$|assword:|login: " send "admin\n" expect "\\$|assword: " send "admin\n" expect "\\$" } script status { send "platform get power state\n" expect "(On|Off)" setplugstate "1" $1 on="On" off="Off" expect "\\$" } script on { send "platform set power state -W -f -q on\n" expect "\\$" delay 3 } script off { send "platform set power state -W -f -q off\n" expect "\\$" delay 3 } script cycle { send "platform set power state -W -f -q off\n" expect "\\$" delay 4 send "platform set power state -W -f -q on\n" expect "\\$" delay 3 } } powerman-2.4.4/etc/devices/openbmc.dev000066400000000000000000000054461467035776500177260ustar00rootroot00000000000000# Support for OpenBMC Rest Interface # # Powerman.conf should look something like this: # include "/etc/powerman/openbmc.dev" # device "openbmc1" "openbmc" "/usr/sbin/httppower -u https://pnode1 -H Content-Type:application/json -c |&" # node "node1" "openbmc1" "pnode1" # # Tested on IBM 8335-GTW w/ firmware ibm-v2.0-0-r46-0-gbed584c. Known issues: # - openbmc's power on/off returns success before the operation has # been completed on the node. The operation typically takes 20-25 # seconds complete. To ensure powerman does not return before the # on/off is completed, we add a delay of 30 seconds. # - httppower can be configured with only one node, so one httppower # co-process is needed for every openbmc node in a cluster. This # can present scalability problems at larger scales. # - There is no background management of up/down status of openbmc # targets. At larger scales, when there will almost always be one # node removed for servicing, and unresponsive target will always # lead to powerman to timeout. # - A longer term solution is being investigated, see: # https://github.com/chaos/powerman/issues/34. # specification "openbmc" { timeout 40 # login uses openbmc default username/password, adjust if necessary script login { expect "httppower> " send "post login {\"data\":[\"root\",\"0penBmc\"]}\n" expect "httppower> " } script logout { send "post logout {\"data\":[]}\n" expect "httppower> " send "quit\n" } script status { send "get xyz/openbmc_project/state/chassis0/attr/CurrentPowerState\n" expect "xyz.openbmc_project.State.Chassis.PowerState.(On|Off)" setplugstate $1 on="On" off="Off" expect "httppower> " } script on { send "put xyz/openbmc_project/state/host0/attr/RequestedHostTransition {\"data\":\"xyz.openbmc_project.State.Host.Transition.On\"}\n" expect "httppower> " delay 30 send "get xyz/openbmc_project/state/chassis0/attr/CurrentPowerState\n" expect "xyz.openbmc_project.State.Chassis.PowerState.On" } # this is a soft power off, hard power off will bring down the bmc script off { send "put xyz/openbmc_project/state/host0/attr/RequestedHostTransition {\"data\":\"xyz.openbmc_project.State.Host.Transition.Off\"}\n" expect "httppower> " delay 30 send "get xyz/openbmc_project/state/chassis0/attr/CurrentPowerState\n" expect "xyz.openbmc_project.State.Chassis.PowerState.Off" } script cycle { send "put xyz/openbmc_project/state/host0/attr/RequestedHostTransition {\"data\":\"xyz.openbmc_project.State.Host.Transition.Reboot\"}\n" expect "httppower> " delay 30 send "get xyz/openbmc_project/state/chassis0/attr/CurrentPowerState\n" expect "xyz.openbmc_project.State.Chassis.PowerState.On" } } powerman-2.4.4/etc/devices/phantom.dev000066400000000000000000000022751467035776500177460ustar00rootroot00000000000000# # Rackable Phantom v3 and v4. # specification "phantom" { timeout 15.0 plug name { "1" } script login { send "\036\035" # enter "shell mode" expect "ok\r" } script status { send "P?" expect "(0|1)\r" setplugstate "1" $1 on="1" off="0" } script on { send "P?" expect "(0|1)\r" setplugstate "1" $1 on="1" off="0" ifoff { send "PT" expect "ok\r" } } script off { send "P?" expect "(0|1)\r" setplugstate "1" $1 on="1" off="0" ifon { send "PT" expect "ok\r" } } script cycle { send "P?" expect "(0|1)\r" setplugstate "1" $1 on="1" off="0" ifon { send "PT" expect "ok\r" delay 4 } send "PT" expect "ok\r" } script beacon_on { send "L1" # LED on expect "ok\r" send "B1" # blink LED expect "ok\r" } script beacon_off { send "L0" # LED off expect "ok\r" send "B0" # unblink LED expect "ok\r" } script status_beacon { send "L?" # get LED status 1=on, 0=off, B=blink expect "(0|1|B)\r" setplugstate "1" $1 on="(B|1)" off="0" } # N.B. phantom 3 requires probe #, phantom 4 ignores it script status_temp { send "T0" # get temp probe 0 expect "([0-9]+)\r" # value is 8-bit Celsius setplugstate "1" $1 } } powerman-2.4.4/etc/devices/plmpower.dev000066400000000000000000000015371467035776500201450ustar00rootroot00000000000000# # Control Insteon/X10 devices via SmartLabs PLM 2412S using the plmpower # utility supplied with powerman, e.g. # # device "plm" "plmpower" "/usr/sbin/plmpower -d /dev/ttyS1 |&" # # Plug names are one of: # - Insteon addresses printed on device xx.xx.xx, e.g. "A4.02.B3" # - X10 address [A-P][1-16], e.g. "G13" # # N.B.: X10 devices will always show power status "unknown". # specification "plmpower" { timeout 10 script login { expect "plmpower> " } script logout { send "quit\n" } script status { send "status %s\n" expect "([^:]+): ([^\n]+)\n" setplugstate $1 $2 off="00" on="[0-9A-F]{2}" expect "plmpower> " } script on { send "on %s\n" expect "plmpower> " } script off { send "off %s\n" expect "plmpower> " } script cycle { send "off %s\n" expect "plmpower> " delay 4 send "on %s\n" expect "plmpower> " } } powerman-2.4.4/etc/devices/powerman.dev000066400000000000000000000020311467035776500201160ustar00rootroot00000000000000# # $Id$ # # PowerMan script for controlling another PowerMan daemon, e.g. # # device "cartman" "powerman" "cartman.llnl.gov:10101" # node "b[1-4]" "cartman" "b[1-4]" # # N.B. master powerman.conf must contain the union of all slave # powerman.conf plugs, or status_all script will not work. # specification "powerman" { timeout 100.0 script login { expect "powerman> " send "exprange\r\n" expect "105 Hostrange expansion ON\r\npowerman> " } script logout { send "quit\r\n" } script status_all { send "status\r\n" foreachplug { expect "303 ([^:]+): (off|on|unknown)\r\n" setplugstate $1 $2 off="off" on="on" } expect "powerman> " } script on_ranged { send "on %s\r\n" expect "powerman> " } script off_ranged { send "off %s\r\n" expect "powerman> " } script cycle_ranged { send "cycle %s\r\n" expect "powerman> " } script reset_ranged { send "reset %s\r\n" expect "powerman> " } } powerman-2.4.4/etc/devices/rancid-cisco-poe.dev000066400000000000000000000026131467035776500214130ustar00rootroot00000000000000# # Control POE on Cisco switches via rancid (http://www.shrubbery.net/rancid/) # # device "cisco-switch" "rancid-cisco-poe" "/usr/lib/rancid/bin/clogin hostname |&" # # Plug names are the device interface name: # node "mydevice" "cisco-switch" "Gi2/0/1" # # The user running the powerman must have a .cloginrc file in its home directory # with an appropriate configuration to allow querying and setting PoE status # specification "rancid-cisco-poe" { timeout 10 script login { expect ".*#" } script logout { send "exit\n" } script status { send "show power inline %s | section (on|off) \n" expect "\r\n([^ ]+) +[^ ]+ +(on|off)" setplugstate $1 $2 off="off" on="on" expect ".*#" } script on { send "conf t\n" expect ".*\\(config\\)#" send "int %s\n" expect ".*\\(config-if\\)#" send "no power inline never\n" expect ".*\\(config-if\\)#" send "end\n" expect ".*#" } script off { send "conf t\n" expect ".*\\(config\\)#" send "int %s\n" expect ".*\\(config-if\\)#" send "power inline never\n" expect ".*\\(config-if\\)#" send "end\n" expect ".*#" } script cycle { send "conf t\n" expect ".*\\(config\\)#" send "int %s\n" expect ".*\\(config-if\\)#" send "power inline never\n" expect ".*\\(config-if\\)#" delay 4 send "no power inline never\n" expect ".*\\(config-if\\)#" send "end\n" expect ".*#" send "off %s\n" expect ".*#" } } powerman-2.4.4/etc/devices/rancid-edgemax-poe.dev000066400000000000000000000026511467035776500217270ustar00rootroot00000000000000# # Control POE on UniFi switches via rancid (http://www.shrubbery.net/rancid/) # # device "ubnt-switch" "rancid-ubnt-poe" "/usr/lib/rancid/bin/clogin -t600 myswitch |&" # # Plug names are the device interface name: # node "mydevice" "ubnt-switch" "0/1" # # The user running the powerman must have a .cloginrc file in its home directory # with an appropriate configuration to allow querying and setting power status # specification "rancid-ubnt-poe" { timeout 10 script login { expect ".*#" } script logout { send "exit\n" } script status { send "show poe status %s | section (Good|Circuit|Short|Low) \n" expect "\r\n\r\n([^ ]+) +(Good|Open Circuit|Short|R Sig Too Low)" setplugstate $1 $2 on="Good" off=".*" expect ".*#" } script on { send "configure\n" expect ".*\\(Config\\)#" send "interface %s\n" expect ".*\\(Interface [0-9\/]+\\)#" send "poe opmode auto\n" expect ".*\\(Interface [0-9\/]+\\)#" send "end\n" expect ".*#" } script off { send "configure\n" expect ".*\\(Config\\)#" send "interface %s\n" expect ".*\\(Interface [0-9\/]+\\)#" send "poe opmode shutdown\n" expect ".*\\(Interface [0-9\/]+\\)#" send "end\n" expect ".*#" } script cycle { send "configure\n" expect ".*\\(Config\\)#" send "interface %s\n" expect ".*\\(Interface [0-9\/]+\\)#" send "poe opmode shutdown poe opmode auto\n" expect ".*\\(Interface [0-9\/]+\\)#" send "end\n" expect ".*#" } } powerman-2.4.4/etc/devices/raritan-px4316.dev000066400000000000000000000027131467035776500207000ustar00rootroot00000000000000# Rariton PX 4316 via SNMP # Example powerman.conf device line: # device "r1" "raritan-px4316" "/usr/sbin/snmppower -h r1|&" # specification "raritan-px4316" { timeout 10 plug name { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" } script login { expect "snmppower> " send "start_v2c private\n" expect "snmppower> " } script logout { send "finish\n" expect "snmppower> " } script status { # -1=error, 0=off, 1=on, 2=cycling send "get enterprises.13742.4.1.2.2.1.3.%s\n" expect "enterprises.13742.4.1.2.2.1.3.([0-9]+): (0|1)" setplugstate $1 $2 on="1" off="0" expect "snmppower> " } # This is really watts! script status_temp { send "get enterprises.13742.4.1.2.2.1.7.%s\n" expect "enterprises.13742.4.1.2.2.1.7.([0-9]+) = Gauge32: ([0-9]+)" setplugstate $1 $2 } script on { send "set enterprises.13742.4.1.2.2.1.3.%s i 1\n" expect "enterprises.13742.4.1.2.2.1.3.[0-9]+: 1\n" expect "snmppower> " delay 0.3 } script off { send "set enterprises.13742.4.1.2.2.1.3.%s i 0\n" expect "enterprises.13742.4.1.2.2.1.3.[0-9]+: 0\n" expect "snmppower> " } script cycle { send "set enterprises.13742.4.1.2.2.1.3.%s i 0\n" expect "enterprises.13742.4.1.2.2.1.3.[0-9]+: 0\n" expect "snmppower> " delay 5 send "set enterprises.13742.4.1.2.2.1.3.%s i 1\n" expect "enterprises.13742.4.1.2.2.1.3.[0-9]+: 1\n" expect "snmppower> " delay 0.3 } } powerman-2.4.4/etc/devices/raritan-px5523.dev000066400000000000000000000030171467035776500206770ustar00rootroot00000000000000# Rariton PX 5523 via SNMP # Example powerman.conf device line: # device "r1" "raritan-px5523" "/usr/sbin/snmppower -h r1|&" # specification "raritan-px5523" { timeout 10 plug name { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "20" "21" "22" "23" "24" } script login { expect "snmppower> " send "start_v2c raritan_private\n" expect "snmppower> " } script logout { send "finish\n" expect "snmppower> " } script status { # -1=error, 0=off, 1=on, 2=cycling send "get enterprises.13742.4.1.2.2.1.3.%s\n" expect "enterprises.13742.4.1.2.2.1.3.([0-9]+): (0|1)" setplugstate $1 $2 on="1" off="0" expect "snmppower> " } # This is really watts! script status_temp { send "get enterprises.13742.4.1.2.2.1.7.%s\n" expect "enterprises.13742.4.1.2.2.1.7.([0-9]+) = Gauge32: ([0-9]+)" setplugstate $1 $2 } script on { send "set enterprises.13742.4.1.2.2.1.3.%s i 1\n" expect "enterprises.13742.4.1.2.2.1.3.[0-9]+: 1\n" expect "snmppower> " delay 0.3 } script off { send "set enterprises.13742.4.1.2.2.1.3.%s i 0\n" expect "enterprises.13742.4.1.2.2.1.3.[0-9]+: 0\n" expect "snmppower> " } script cycle { send "set enterprises.13742.4.1.2.2.1.3.%s i 0\n" expect "enterprises.13742.4.1.2.2.1.3.[0-9]+: 0\n" expect "snmppower> " delay 5 send "set enterprises.13742.4.1.2.2.1.3.%s i 1\n" expect "enterprises.13742.4.1.2.2.1.3.[0-9]+: 1\n" expect "snmppower> " delay 0.3 } } powerman-2.4.4/etc/devices/redfish-supermicro.dev000066400000000000000000000040221467035776500221020ustar00rootroot00000000000000# Support for Redfish Rest Interface # # Powerman.conf should look something like this: # include "/etc/powerman/redfish-supermicro.dev" # device "redfish1" "redfish-supermicro" "/usr/sbin/httppower -u https://pnode1 -H Content-Type:application/json |&" # node "node1" "redfish1" "pnode1" # # - Set your system's username/password in the login section below # # - This device specification was tested on a Supermicro H12DSG-O-CPU. # # - If using a slightly different model or BMC firmware version, its # possible the URI paths will be different. A good starting point # is to run the following command to discover the correct paths: # # curl -s -u USER:PASS -k -X GET https://pnode1/redfish/v1/Systems/1 # # - This device specification has been supplanted by # redfishpower-supermicro.dev, which does not require fragile delays # to ensure power operations are complete before the script # returns. Users should migrate to the new one. # specification "redfish-supermicro" { timeout 40 script login { expect "httppower> " send "auth USER:PASS\n" expect "httppower> " } script logout { send "quit\n" } script status { send "get redfish/v1/Systems/1/\n" expect "\"PowerState\":\"(On|Off)\"" setplugstate $1 on="On" off="Off" expect "httppower> " } script on { send "post redfish/v1/Systems/1/Actions/ComputerSystem.Reset {\"ResetType\":\"On\"}\n" expect "httppower> " delay 30 send "get redfish/v1/Systems/1/\n" expect "\"PowerState\":\"On\"" } script off { send "post redfish/v1/Systems/1/Actions/ComputerSystem.Reset {\"ResetType\":\"ForceOff\"}\n" expect "httppower> " delay 30 send "get redfish/v1/Systems/1/\n" expect "\"PowerState\":\"Off\"" } script cycle { send "post redfish/v1/Systems/1/Actions/ComputerSystem.Reset {\"ResetType\":\"ForceRestart\"}\n" expect "httppower> " delay 30 send "get redfish/v1/Systems/1/\n" expect "\"PowerState\":\"On\"" } } powerman-2.4.4/etc/devices/redfishpower-cray-ex-rabbit.dev000066400000000000000000000114131467035776500236020ustar00rootroot00000000000000# This is a variant of the cray-ex chassis populated with rabbit # storage hardware. Refer to cray-ex for info specific to that # chassis. # # - If necessary, set your system's username/password via redfishpower's # --auth option. # # - Assuming all blades are populated with nodes, switch slots 0-3 are # populated with switches, and switch slots 4 & 7 are populated by a # rabbit, configure in Powerman like below. # # N.B. A rabbit takes up 4 switch slots but only utilizes power from # slots 4 & 7. Slot 4 powers storage/drives, slot 7 powers processor. # # Take special notice to the order of hosts listed with `-h` as the # order matters (plugnames are mapped to hosts via indices). The cmm # should be listed first with the 16 nodes second. # # include "/etc/powerman/redfishpower-cray-ex-rabbit.dev" # device "chassis0" "cray-ex" "/usr/sbin/redfishpower -h cmm0,pmynode[0-15],rabbit |&" # node "cmm0,myperif[0-3],rabbit-storage,rabbit-blade,myblade[0-7],mynode[0-15],rabbit" "chassis0" "Enclosure,Perif[0-4,7],Blade[0-7],Node[0-16]" # # - If your chassis is not fully populated, put placeholder hosts in # the redfishpower hosts configuration. Adjust plugs when # configuring specific targets. For example, let's say blades[4-7] # are not populated (thus nodes[8-15] also do not exist). # # device "chassis0" "cray-ex" "/usr/sbin/redfishpower -h cmm0,pnode[0-7],unused[0-7],rabbit |&" # node "cmm0,myperif[0-3],rabbit-storage,rabbit-blade,myblade[0-3],mynode[0-7],rabbit" "chassis0" "Enclosure,Perif[0-4.7],Blade[0-3],Node[0-7,16]" # specification "cray-ex-rabbit" { timeout 100 plug name { "Enclosure" "Perif0" "Perif1" "Perif2" "Perif3" "Perif4" # "Perif5" storage hardware - no power control # "Perif6" storage hardware - no power control "Perif7" "Blade0" "Blade1" "Blade2" "Blade3" "Blade4" "Blade5" "Blade6" "Blade7" "Node0" "Node1" "Node2" "Node3" "Node4" "Node5" "Node6" "Node7" "Node8" "Node9" "Node10" "Node11" "Node12" "Node13" "Node14" "Node15" # Node16 is slotted into Perif7 "Node16" } script login { expect "redfishpower> " send "auth operator:initial0_op\n" expect "redfishpower> " send "setheader Content-Type:application/json\n" expect "redfishpower> " # setplugs plugnames hostindices [parentplug] send "setplugs Enclosure 0\n" expect "redfishpower> " send "setplugs Perif[0-4,7],Blade[0-7] 0 Enclosure\n" expect "redfishpower> " send "setplugs Node[0-1] [1-2] Blade0\n" expect "redfishpower> " send "setplugs Node[2-3] [3-4] Blade1\n" expect "redfishpower> " send "setplugs Node[4-5] [5-6] Blade2\n" expect "redfishpower> " send "setplugs Node[6-7] [7-8] Blade3\n" expect "redfishpower> " send "setplugs Node[8-9] [9-10] Blade4\n" expect "redfishpower> " send "setplugs Node[10-11] [11-12] Blade5\n" expect "redfishpower> " send "setplugs Node[12-13] [13-14] Blade6\n" expect "redfishpower> " send "setplugs Node[14-15] [15-16] Blade7\n" expect "redfishpower> " send "setplugs Node16 17 Perif7\n" expect "redfishpower> " # setpath [postdata] send "setpath Enclosure,Perif[0-4,7],Blade[0-7] stat redfish/v1/Chassis/{{plug}}\n" expect "redfishpower> " send "setpath Enclosure,Perif[0-4,7],Blade[0-7] on redfish/v1/Chassis/{{plug}}/Actions/Chassis.Reset {\"ResetType\":\"On\"}\n" expect "redfishpower> " send "setpath Enclosure,Perif[0-4,7],Blade[0-7] off redfish/v1/Chassis/{{plug}}/Actions/Chassis.Reset {\"ResetType\":\"ForceOff\"}\n" expect "redfishpower> " send "setpath Node[0-16] stat redfish/v1/Systems/Node0\n" expect "redfishpower> " send "setpath Node[0-16] on redfish/v1/Systems/Node0/Actions/ComputerSystem.Reset {\"ResetType\":\"On\"}\n" expect "redfishpower> " send "setpath Node[0-16] off redfish/v1/Systems/Node0/Actions/ComputerSystem.Reset {\"ResetType\":\"ForceOff\"}\n" expect "redfishpower> " # settimeout - on/off operations fail on expiration send "settimeout 75\n" expect "redfishpower> " } script logout { send "quit\n" } script status { send "stat %s\n" expect "([^\n:]+): ([^\n]+\n)" setplugstate $1 $2 on="^on\n" off="^off\n" expect "redfishpower> " } script status_all { send "stat\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setplugstate $1 $2 on="^on\n" off="^off\n" } expect "redfishpower> " } script on_ranged { send "on %s\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setresult $1 $2 success="^ok\n" } expect "redfishpower> " } script off_ranged { send "off %s\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setresult $1 $2 success="^ok\n" } expect "redfishpower> " } script cycle_ranged { send "off %s\n" expect "redfishpower> " delay 2 send "on %s\n" expect "redfishpower> " } } powerman-2.4.4/etc/devices/redfishpower-cray-ex.dev000066400000000000000000000106631467035776500223470ustar00rootroot00000000000000# Support for Redfish Rest Interface # # How blades and switches in a HPE Cray Supercomputing EX Chassis # (abbreviated CrayEX) are populated has a large effect on # configuration. Tweaks to this device file may be needed. See the # section "UPDATING REDFISHPOWER DEVICE FILES" in redfishpower(8) for # additional tips. # # - If necessary, set your system's username/password via redfishpower's # --auth option. # # - Assuming all blades are populated with nodes and all switches are # populated, configure in Powerman like below. # # Take special notice to the order of hosts listed with `-h` as the # order matters (plugnames are mapped to hosts via indices). The cmm # should be listed first with the 16 nodes second. # # include "/etc/powerman/redfishpower-cray-ex.dev" # device "chassis0" "cray-ex" "/usr/sbin/redfishpower -h cmm0,pmynode[0-15] |&" # node "cmm0,myperif[0-7],myblade[0-7],mynode[0-15]" "chassis0" "Enclosure,Perif[0-7],Blade[0-7],Node[0-15]" # # - If your chassis is not fully populated, put placeholder hosts in # the redfishpower hosts configuration. Adjust plugs when # configuring specific targets. For example, let's say blades[4-7] # are not populated (thus nodes[8-15] also do not exist). # # device "chassis0" "cray-ex" "/usr/sbin/redfishpower -h cmm0,pnode[0-7],unused[0-7] |&" # node "cmm0,myperif[0-7],myblade[0-3],mynode[0-7]" "chassis0" "Enclosure,Perif[0-7],Blade[0-3],Node[0-7]" # specification "cray-ex" { timeout 100 plug name { "Enclosure" "Perif0" "Perif1" "Perif2" "Perif3" "Perif4" "Perif5" "Perif6" "Perif7" "Blade0" "Blade1" "Blade2" "Blade3" "Blade4" "Blade5" "Blade6" "Blade7" "Node0" "Node1" "Node2" "Node3" "Node4" "Node5" "Node6" "Node7" "Node8" "Node9" "Node10" "Node11" "Node12" "Node13" "Node14" "Node15" } script login { expect "redfishpower> " send "auth operator:initial0_op\n" expect "redfishpower> " send "setheader Content-Type:application/json\n" expect "redfishpower> " # setplugs plugnames hostindices [parentplug] send "setplugs Enclosure 0\n" expect "redfishpower> " send "setplugs Perif[0-7],Blade[0-7] 0 Enclosure\n" expect "redfishpower> " send "setplugs Node[0-1] [1-2] Blade0\n" expect "redfishpower> " send "setplugs Node[2-3] [3-4] Blade1\n" expect "redfishpower> " send "setplugs Node[4-5] [5-6] Blade2\n" expect "redfishpower> " send "setplugs Node[6-7] [7-8] Blade3\n" expect "redfishpower> " send "setplugs Node[8-9] [9-10] Blade4\n" expect "redfishpower> " send "setplugs Node[10-11] [11-12] Blade5\n" expect "redfishpower> " send "setplugs Node[12-13] [13-14] Blade6\n" expect "redfishpower> " send "setplugs Node[14-15] [15-16] Blade7\n" expect "redfishpower> " # setpath [postdata] send "setpath Enclosure,Perif[0-7],Blade[0-7] stat redfish/v1/Chassis/{{plug}}\n" expect "redfishpower> " send "setpath Enclosure,Perif[0-7],Blade[0-7] on redfish/v1/Chassis/{{plug}}/Actions/Chassis.Reset {\"ResetType\":\"On\"}\n" expect "redfishpower> " send "setpath Enclosure,Perif[0-7],Blade[0-7] off redfish/v1/Chassis/{{plug}}/Actions/Chassis.Reset {\"ResetType\":\"ForceOff\"}\n" expect "redfishpower> " send "setpath Node[0-15] stat redfish/v1/Systems/Node0\n" expect "redfishpower> " send "setpath Node[0-15] on redfish/v1/Systems/Node0/Actions/ComputerSystem.Reset {\"ResetType\":\"On\"}\n" expect "redfishpower> " send "setpath Node[0-15] off redfish/v1/Systems/Node0/Actions/ComputerSystem.Reset {\"ResetType\":\"ForceOff\"}\n" expect "redfishpower> " # settimeout - on/off operations fail on expiration send "settimeout 75\n" expect "redfishpower> " } script logout { send "quit\n" } script status { send "stat %s\n" expect "([^\n:]+): ([^\n]+\n)" setplugstate $1 $2 on="^on\n" off="^off\n" expect "redfishpower> " } script status_all { send "stat\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setplugstate $1 $2 on="^on\n" off="^off\n" } expect "redfishpower> " } script on_ranged { send "on %s\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setresult $1 $2 success="^ok\n" } expect "redfishpower> " } script off_ranged { send "off %s\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setresult $1 $2 success="^ok\n" } expect "redfishpower> " } script cycle_ranged { send "off %s\n" expect "redfishpower> " delay 2 send "on %s\n" expect "redfishpower> " } } powerman-2.4.4/etc/devices/redfishpower-cray-r272z30.dev000066400000000000000000000033141467035776500227570ustar00rootroot00000000000000# Support for Redfish Rest Interface # # Powerman.conf should look something like this: # include "/etc/powerman/redfishpower-cray-r272z30.dev" # device "redfishpower" "redfishpower-cray-r272z30" "/usr/sbin/redfishpower -h pnode[1-2] |&" # node "node1" "redfishpower" "pnode1" # node "node2" "redfishpower" "pnode2" # # - If necessary, set your system's username/password via redfishpower's # --auth option. # # - This device specification was tested on a Cray with Gigabyte R272-Z30. # # - CAUTION: If you intend to use this file as the basis for a different # Redfish system, read the section "UPDATING REDFISHPOWER DEVICE FILES" # in redfishpower(8). # specification "redfishpower-cray-r272z30" { timeout 60 script login { expect "redfishpower> " send "auth USER:PASS\n" expect "redfishpower> " send "setheader Content-Type:application/json\n" expect "redfishpower> " send "setstatpath redfish/v1/Systems/Self\n" expect "redfishpower> " send "setonpath redfish/v1/Systems/Self/Actions/ComputerSystem.Reset {\"ResetType\":\"On\"}\n" expect "redfishpower> " send "setoffpath redfish/v1/Systems/Self/Actions/ComputerSystem.Reset {\"ResetType\":\"ForceOff\"}\n" expect "redfishpower> " send "settimeout 60\n" expect "redfishpower> " } script logout { send "quit\n" } script status_all { send "stat\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setplugstate $1 $2 on="^on\n" off="^off\n" } expect "redfishpower> " } script on_ranged { send "on %s\n" expect "redfishpower> " } script off_ranged { send "off %s\n" expect "redfishpower> " } script cycle_ranged { send "off %s\n" expect "redfishpower> " delay 2 send "on %s\n" expect "redfishpower> " } } powerman-2.4.4/etc/devices/redfishpower-cray-windom.dev000066400000000000000000000063151467035776500232270ustar00rootroot00000000000000# Support for Redfish Rest Interface # # Powerman.conf should look something like this: # include "/etc/powerman/redfishpower-cray-windom.dev" # device "redfishpower0" "redfishpower-cray-windom-node0" "/usr/sbin/redfishpower -h pnode[1,3] |&" # device "redfishpower1" "redfishpower-cray-windom-node1" "/usr/sbin/redfishpower -h pnode[2,4] |&" # node "node1" "redfishpower0" "pnode1" # node "node2" "redfishpower1" "pnode2" # node "node3" "redfishpower0" "pnode3" # node "node4" "redfishpower1" "pnode4" # # - If necessary, set your system's username/password via redfishpower's # --auth option. # # - This device specification was tested on a Cray Windom. # # - Two specifications are listed below with a slightly different URI # suffix ("Node0" vs "Node1") depending on the specific node # attached to a blade's service processor. Some experimentation may # be needed to determine which node is attached to which suffix. # # - CAUTION: If you intend to use this file as the basis for a different # Redfish system, read the section "UPDATING REDFISHPOWER DEVICE FILES" # in redfishpower(8). # specification "redfishpower-cray-windom-node0" { timeout 60 script login { expect "redfishpower> " send "auth USER:PASS\n" expect "redfishpower> " send "setheader Content-Type:application/json\n" expect "redfishpower> " send "setstatpath redfish/v1/Systems/Node0\n" expect "redfishpower> " send "setonpath redfish/v1/Systems/Node0/Actions/ComputerSystem.Reset {\"ResetType\":\"On\"}\n" expect "redfishpower> " send "setoffpath redfish/v1/Systems/Node0/Actions/ComputerSystem.Reset {\"ResetType\":\"ForceOff\"}\n" expect "redfishpower> " send "settimeout 60\n" expect "redfishpower> " } script logout { send "quit\n" } script status_all { send "stat\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setplugstate $1 $2 on="^on\n" off="^off\n" } expect "redfishpower> " } script on_ranged { send "on %s\n" expect "redfishpower> " } script off_ranged { send "off %s\n" expect "redfishpower> " } script cycle_ranged { send "off %s\n" expect "redfishpower> " delay 2 send "on %s\n" expect "redfishpower> " } } specification "redfishpower-cray-windom-node1" { timeout 60 script login { expect "redfishpower> " send "auth USER:PASS\n" expect "redfishpower> " send "setheader Content-Type:application/json\n" expect "redfishpower> " send "setstatpath redfish/v1/Systems/Node1\n" expect "redfishpower> " send "setonpath redfish/v1/Systems/Node1/Actions/ComputerSystem.Reset {\"ResetType\":\"On\"}\n" expect "redfishpower> " send "setoffpath redfish/v1/Systems/Node1/Actions/ComputerSystem.Reset {\"ResetType\":\"ForceOff\"}\n" expect "redfishpower> " send "settimeout 60\n" expect "redfishpower> " } script logout { send "quit\n" } script status_all { send "stat\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setplugstate $1 $2 on="^on\n" off="^off\n" } expect "redfishpower> " } script on_ranged { send "on %s\n" expect "redfishpower> " } script off_ranged { send "off %s\n" expect "redfishpower> " } script cycle_ranged { send "off %s\n" expect "redfishpower> " delay 2 send "on %s\n" expect "redfishpower> " } } powerman-2.4.4/etc/devices/redfishpower-supermicro.dev000066400000000000000000000032711467035776500231640ustar00rootroot00000000000000# Support for Redfish Rest Interface # # Powerman.conf should look something like this: # include "/etc/powerman/redfishpower-supermicro.dev" # device "redfishpower" "redfishpower-supermicro" "/usr/sbin/redfishpower -h pnode[1-2] |&" # node "node1" "redfishpower" "pnode1" # node "node2" "redfishpower" "pnode2" # # - If necessary, set your system's username/password via redfishpower's # --auth option. # # - This device specification was tested on a Supermicro H12DSG-O-CPU. # # - CAUTION: If you intend to use this file as the basis for a different # Redfish system, read the section "UPDATING REDFISHPOWER DEVICE FILES" # in redfishpower(8). # specification "redfishpower-supermicro" { timeout 60 script login { expect "redfishpower> " send "auth USER:PASS\n" expect "redfishpower> " send "setheader Content-Type:application/json\n" expect "redfishpower> " send "setstatpath redfish/v1/Systems/1\n" expect "redfishpower> " send "setonpath redfish/v1/Systems/1/Actions/ComputerSystem.Reset {\"ResetType\":\"On\"}\n" expect "redfishpower> " send "setoffpath redfish/v1/Systems/1/Actions/ComputerSystem.Reset {\"ResetType\":\"ForceOff\"}\n" expect "redfishpower> " send "settimeout 60\n" expect "redfishpower> " } script logout { send "quit\n" } script status_all { send "stat\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setplugstate $1 $2 on="^on\n" off="^off\n" } expect "redfishpower> " } script on_ranged { send "on %s\n" expect "redfishpower> " } script off_ranged { send "off %s\n" expect "redfishpower> " } script cycle_ranged { send "off %s\n" expect "redfishpower> " delay 2 send "on %s\n" expect "redfishpower> " } } powerman-2.4.4/etc/devices/sentry_cdu.dev000066400000000000000000000106351467035776500204560ustar00rootroot00000000000000# Sentry Switched CDU Version 6.0r specification "sentry_cdu" { timeout 10 plug name { ".AA1" ".AA2" ".AA3" ".AA4" ".AA5" ".AA6" ".AA7" ".AA8" ".AB1" ".AB2" ".AB3" ".AB4" ".AB5" ".AB6" ".AB7" ".AB8" ".AC1" ".AC2" ".AC3" ".AC4" ".AC5" ".AC6" ".AC7" ".AC8" } script login { expect "Username: " send "admn\r\n" expect "Password: " send "admn\r\n" expect "Switched CDU: " } script logout { send "logout\r\n" } script status_all { send "status\r\n" expect "\.AA1[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AA1" $1 on="On" off="Off" expect "\.AA2[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AA2" $1 on="On" off="Off" expect "\.AA3[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AA3" $1 on="On" off="Off" expect "\.AA4[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AA4" $1 on="On" off="Off" expect "\.AA5[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AA5" $1 on="On" off="Off" expect "\.AA6[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AA6" $1 on="On" off="Off" expect "\.AA7[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AA7" $1 on="On" off="Off" expect "\.AA8[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AA8" $1 on="On" off="Off" expect "\.AB1[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AB1" $1 on="On" off="Off" expect "\.AB2[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AB2" $1 on="On" off="Off" expect "\.AB3[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AB3" $1 on="On" off="Off" expect "\.AB4[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AB4" $1 on="On" off="Off" expect "\.AB5[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AB5" $1 on="On" off="Off" expect "\.AB6[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AB6" $1 on="On" off="Off" expect "\.AB7[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AB7" $1 on="On" off="Off" expect "\.AB8[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AB8" $1 on="On" off="Off" expect "More \\(Y/es N/o\\):" send "y" expect "y\r\n\r\n" expect "\.AC1[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AC1" $1 on="On" off="Off" expect "\.AC2[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AC2" $1 on="On" off="Off" expect "\.AC3[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AC3" $1 on="On" off="Off" expect "\.AC4[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AC4" $1 on="On" off="Off" expect "\.AC5[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AC5" $1 on="On" off="Off" expect "\.AC6[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AC6" $1 on="On" off="Off" expect "\.AC7[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AC7" $1 on="On" off="Off" expect "\.AC8[^\r\n]*(On|Off) *(On|Off) *\r\n" setplugstate ".AC8" $1 on="On" off="Off" expect "Command successful" expect "\r\n\r\nSwitched CDU: " } script on { send "on %s\r\n" expect "Switched CDU: " } script on_all { send "on all\r\n" expect "More \\(Y/es N/o\\):" send "y" expect "y\r\n\r\n" expect "Switched CDU: " } script off { send "off %s\r\n" expect "Switched CDU: " } script off_all { send "off all\r\n" expect "More \\(Y/es N/o\\):" send "y" expect "y\r\n\r\n" expect "Switched CDU: " } script cycle { send "off %s\r\n" expect "Switched CDU: " delay 4 send "on %s\r\n" expect "Switched CDU: " } script cycle_all { send "off all\r\n" expect "More \\(Y/es N/o\\):" send "y" expect "y\r\n\r\n" expect "Switched CDU: " delay 4 send "on all\r\n" expect "More \\(Y/es N/o\\):" send "y" expect "y\r\n\r\n" expect "Switched CDU: " } } powerman-2.4.4/etc/devices/swpdu.dev000066400000000000000000000017441467035776500174420ustar00rootroot00000000000000# # Appro SWPDU # # swpdu.dev,v 1.0 2007/11/07 23:50:34 kolee APPRO # /etc/powerman/swpdu.dev,v # specification "swpdu" { timeout 20.0 plug name { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "20" "21" "22" "23" "24" "25" "26" "27" "28" "29" "30" "31" "32" "33" "34" "35" "36" "37" "38" "39" "40" "41" "42" "43" "44" "45" "46" "47" "48" } script ping { send "\r\n" expect "swpdu> " } script login { # expect "Password:" # send "111111\r\n" send "\r\n" expect "swpdu> " send "exprange on\r\n" expect "swpdu> " } script logout { send "exprange off\r\n" expect "swpdu> " } script status_all { send "status\r\n" foreachplug { expect "port([0-9]+)[^\n]*(on|off|unknown|^n)" setplugstate $1 $2 on="on" off="off" } expect "swpdu> " } script on { send "on %s\r\n" expect "swpdu> " } script off { send "off %s\r\n" expect "swpdu> " } script cycle { send "cycle %s\r\n" expect "swpdu> " } } powerman-2.4.4/etc/devices/wti-rps10.dev000066400000000000000000000022651467035776500200450ustar00rootroot00000000000000# # $Id$ # # WTI RPS-10 # # Master configured for 9600 baud: # if 9600 - wait 0.5 sec before sending next command # if 2400 - wait 1.5 sec before sending next command # Format of commands is ^X^X^B^X^X^B^X^XPC\r # where P is port number (0-9) and C is command (0,1,T,?) # # N.B. The 0.5 sec delays mentioned in the documentation don't seem to be # needed on my setup... # specification "wti-rps10" { timeout 5 plug name { "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" } script login { delay 2 } script status { send "\030\030\002\030\030\002\030\030%s?\r" expect "Plug ([0-9]) (On|Off)" setplugstate $1 $2 off="Off" on="On" expect "Complete" } script on { send "\030\030\002\030\030\002\030\030%s1\r" expect "Plug [0-9] On" expect "Complete" } script off { send "\030\030\002\030\030\002\030\030%s0\r" expect "Plug [0-9] Off" expect "Complete" } # The T command is dip switch configurable for 5 or 10 second delay # Shorter delays have to be done in s/w. script cycle { send "\030\030\002\030\030\002\030\030%s0\r" expect "Plug [0-9] Off" expect "Complete" delay 4 send "\030\030\002\030\030\002\030\030%s1\r" expect "Plug [0-9] On" expect "Complete" } } powerman-2.4.4/etc/devices/wti.dev000066400000000000000000000022201467035776500170710ustar00rootroot00000000000000# # $Id$ # # WTI NPS # # Tested the following firmware versions: # v3.02 # Assumes: # 1. password: "wti" (/g general params, 1 system passwd) # 2. command confirmation: off (/g general params, 8 command confirmation) # 3. disconnect timeout: set to max (30 min) # Note: prompt is not returned until device is ready to accept another command # specification "wti" { timeout 30 # "/boot *" command takes about 20 sec plug name { "1" "2" "3" "4" "5" "6" "7" "8" } script login { expect "\n" expect "word: " send "wti\r\n" expect "NPS> " } script logout { send "/x\r\n" } script status_all { send "/s\r\n" expect "Default" expect "\\+\r\n" foreachplug { expect " ([0-9]+)[^\n]*(ON|OFF)[^\n]*(ON|OFF)[^\n]*\r\n" setplugstate $1 $2 off="OFF" on="ON" } expect "\\+\r\n" expect "NPS> " } script on { send "/on %s\r\n" expect "NPS> " } script on_all { send "/on *\r\n" expect "NPS> " } script off { send "/off %s\r\n" expect "NPS> " } script off_all { send "/off *\r\n" expect "NPS> " } script cycle { send "/boot %s\r\n" expect "NPS> " } script cycle_all { send "/boot *\r\n" expect "NPS> " } } powerman-2.4.4/etc/libpowerman.pc.in000066400000000000000000000003671467035776500174260ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libpowerman Description: Centralized Power Distribution Unit (PDU) management Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lpowerman Cflags: -I${includedir} powerman-2.4.4/etc/powerman.conf.example000066400000000000000000000101551467035776500203030ustar00rootroot00000000000000# Example powerman.conf file - see powerman.conf(1) # Uncomment to enable TCP wrappers #tcpwrappers yes # Uncomment to listen on all ports (default is 127.0.0.1:10101) #listen "0.0.0.0:10101" # Uncomment to set syslog level for power on/off/reset/cycle requests # (default is debug). Accepts the same level strings as logger(1). #plug_log_level "info" # Include device specifications for power controllers #include "/etc/powerman/apc7900.dev" #include "/etc/powerman/apc.dev" #include "/etc/powerman/apcnew.dev" #include "/etc/powerman/apcold.dev" #include "/etc/powerman/apcpdu3.dev" #include "/etc/powerman/apcpdu.dev" #include "/etc/powerman/bashfun.dev" #include "/etc/powerman/baytech.dev" #include "/etc/powerman/baytech-rpc28-nc.dev" #include "/etc/powerman/baytech-rpc3-nc.dev" #include "/etc/powerman/cb-7050.dev" #include "/etc/powerman/cyclades-pm10.dev" #include "/etc/powerman/cyclades-pm20.dev" #include "/etc/powerman/cyclades-pm42.dev" #include "/etc/powerman/cyclades-pm8.dev" #include "/etc/powerman/dli.dev" #include "/etc/powerman/hp3488.dev" #include "/etc/powerman/hpilo.dev" #include "/etc/powerman/hpmpblade.dev" #include "/etc/powerman/hpmpcell.dev" #include "/etc/powerman/hpmp.dev" #include "/etc/powerman/hpmpdome.dev" #include "/etc/powerman/ibmbladecenter.dev" #include "/etc/powerman/icebox3.dev" #include "/etc/powerman/icebox.dev" #include "/etc/powerman/ics8064.dev" #include "/etc/powerman/ilom.dev" #include "/etc/powerman/ipmi.dev" #include "/etc/powerman/ipmipower.dev" #include "/etc/powerman/lom.dev" #include "/etc/powerman/phantom.dev" #include "/etc/powerman/plmpower.dev" #include "/etc/powerman/powerman.dev" #include "/etc/powerman/swpdu.dev" #include "/etc/powerman/wti.dev" #include "/etc/powerman/wti-rps10.dev" # Define devices (instances of power controllers) # - Network-attached devices use the form: # device "name" "type" "host:port" # - Serial-attached devices use the form # device "name" "type" "special file" "flags" # where "flags" specifies baud and params such as "9600,8n1" # - Devices that are accessed via coprocesses use the form # device "name" "type" "executable-path [args...] |&" # - The "name" field should be unique, and will be referenced in node defs. # - The "type" field should match the quoted string at the beginning of # the device specification. #device "b1" "baytech-rpc28-nc" "cyclades1:7032" #device "b2" "baytech-rpc28-nc" "cyclades1:7016" #device "b3" "baytech-rpc28-nc" "/usr/bin/conman -j -Q b3 |&" #device "b4" "baytech-rpc3-nc" "baytech4:23" #device "lpc" "dli" "/usr/sbin/httppower -u http://192.168.0.100 |&" #device "plm" "plmpower" "/usr/sbin/plmpower -d /dev/ttyS1 |&" #device "wti1" "wti-rps10" "/dev/ttyS0" "9600,8n1" #device "wti2" "wti-rps10" "/dev/ttyS2" "9600,8n1" #device "ipmi1" "ipmipower" "/usr/sbin/ipmipower --wait-until-on --wait-until-off -h py[0-10] |&" # Define nodes (the entities you turn on and off with powerman) # - The longhand form is one line per node like this: # node "node" "device" "plug" # where "node" is the name you will use to refer to the node, # "device" refers to the name you assigned above to the device the # node is plugged into, and "plug" is the (device specific) plug identifier # defined in the "plug name" portion of the device specification or # otherwise following the pattern expected by that device. # - It is possible to use hostranges to map ranges of nodes to ranges # of plugs as follows: # node "noderange" "device" "plugrange" # - And if you just want to assign all the plugs in order, you can drop # the plug range: # node "noderange" "device" #node "t1" "b1" "4" # first four plugs of 'b1' wired backwards #node "t2" "b1" "3" #node "t3" "b1" "2" #node "t4" "b1" "1" #node "t[5-20]" "b1" "[5-20]" #node "t[21-40]" "b2" #node "t[41-60]" "b3" #node "x[1-8]" "lpc" #node "y[0-10]" "ipmi1" "py[0-10]" #node "porchlight" "plm" "A4.02.B3" #node "kitchen" "plm" "A4.97.44" #node "lamp" "plm" "G13" # Aliases can be used to make new names for plugs, or to have one name # refer to redundant power supplies. #node "jimmy-ps1" "wti1" "7" #node "jimmy-ps2" "wti2" "7" #alias "jimmy" "jimmy-ps[1-2]" powerman-2.4.4/etc/powerman.service.in000066400000000000000000000003411467035776500177650ustar00rootroot00000000000000[Unit] Description=PowerMan After=syslog.target network.target [Service] Environment=SHELL=/bin/sh PrivateTmp=yes User=@RUN_AS_USER@ Group=@RUN_AS_GROUP@ ExecStart=@X_SBINDIR@/powermand [Install] WantedBy=multi-user.target powerman-2.4.4/examples/000077500000000000000000000000001467035776500152135ustar00rootroot00000000000000powerman-2.4.4/examples/powerman_el72.spec.in000066400000000000000000000073261467035776500211650ustar00rootroot00000000000000Name: @PACKAGE_NAME@ Version: @PACKAGE_VERSION@ Release: 1%{?dist} Summary: PowerMan - centralized power control for clusters License: GPL Group: Applications/System Url: http://github.com/chaos/powerman Source0: %{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: tcp_wrappers-devel BuildRequires: libgenders-devel BuildRequires: curl-devel BuildRequires: net-snmp-devel BuildRequires: systemd %package devel Requires: %{name} = %{version}-%{release} Summary: Headers and libraries for developing applications using PowerMan Group: Development/Libraries %package libs Requires: %{name} = %{version}-%{release} Summary: Libraries for applications using PowerMan Group: System Environment/Libraries %description PowerMan is a tool for manipulating remote power control (RPC) devices from a central location. Several RPC varieties are supported natively by PowerMan and Expect-like configurability simplifies the addition of new devices. %description devel A header file and static library for developing applications using PowerMan. %description libs A shared library for applications using PowerMan. %prep %setup %build %configure \ --with-genders \ --with-httppower \ --with-snmppower \ --with-tcp-wrappers \ --with-systemdsystemunitdir=%{_unitdir} \ --program-prefix=%{?_program_prefix:%{_program_prefix}} make %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT %clean rm -rf $RPM_BUILD_ROOT %post /bin/systemctl enable powerman > /dev/null 2>&1 ||: %post libs if [ -x /sbin/ldconfig ]; then /sbin/ldconfig %{_libdir}; fi %preun if [ "$1" = 0 ]; then systemctl stop powerman >/dev/null 2>&1 || : systemctl disable powerman > /dev/null 2>&1 || : fi %postun if [ "$1" -ge 1 ]; then systemctl try-restart powerman >/dev/null 2>&1 || : fi %postun libs if [ -x /sbin/ldconfig ]; then /sbin/ldconfig %{_libdir}; fi %files %defattr(-,root,root,0755) %doc DISCLAIMER %doc COPYING %doc NEWS %doc TODO %{_bindir}/powerman %{_bindir}/pm %{_sbindir}/powermand %{_sbindir}/vpcd %{_sbindir}/httppower %{_sbindir}/snmppower %{_sbindir}/plmpower %dir %config %{_sysconfdir}/powerman %{_sysconfdir}/powerman/*.dev %{_sysconfdir}/powerman/powerman.conf.example %{_mandir}/*1/* %{_mandir}/*5/* %{_mandir}/*8/* %{_libdir}/stonith/plugins/external/powerman %{_unitdir}/powerman.service %{_tmpfilesdir}/powerman.conf %files devel %defattr(-,root,root,0755) %{_includedir}/* %{_libdir}/*.la %{_mandir}/*3/* %{_libdir}/*.a %{_libdir}/*.so %{_libdir}/pkgconfig/* %files libs %defattr(-,root,root,0755) %{_libdir}/*.so.* %changelog * Wed Mar 08 2017 Brian J. Murrell 2.3.25-1 - Move the powerman.spec to the examples dir and rename it to powerman_el72.spec to indicate that this spec is just an example that works on EL7.2 * Fri Oct 23 2015 Jim Garlick 2.3.24-1 - Don't package /var/run/powerman; let systemd manage this directory. * Fri May 29 2015 Jim Garlick 2.3.23-1 - Drop conditional builds as full build works everywhere now, more or less - Drop AIX library handling conditionals (unused?) * Fri May 29 2015 Jim Garlick 2.3.20-1 - Switch to systemd init * Tue Feb 14 2006 Ben Woodard 1.0.22-3 - Changed /usr/bin to bindir - Changed /usr/sbin to sbindir - Added COPYING to list of docs. - Changed /etc/rc.d/init.d/ to initrddir - Changed /usr/man to mandir - Added a fully qualified path to the source file. - Fixed buildroot - Added a patch which should fix a fc4 build problem. * Thu Feb 09 2006 Ben Woodard 1.0.22-2 - changed the buildroot to match fedora guidelines - changed permissions of spec and src files. - added changelog to spec file powerman-2.4.4/heartbeat/000077500000000000000000000000001467035776500153345ustar00rootroot00000000000000powerman-2.4.4/heartbeat/Makefile.am000066400000000000000000000001471467035776500173720ustar00rootroot00000000000000hblibdir = $(libdir)/stonith/plugins/external hblib_SCRIPTS = powerman EXTRA_DIST = $(hblib_SCRIPTS) powerman-2.4.4/heartbeat/powerman000077500000000000000000000051401467035776500171120ustar00rootroot00000000000000#!/bin/bash # # heartbeat STONITH module for powerman # # Usage: powerman-stonith [on|off|reset|status] plug # # $serverhost - host:port of powerman server (required) # $poweroff - set to 1 if 'reset' should simply power off (optional) # $PM_OVERRIDE - (undocumented, for test) override powerman path # $PM_VERBOSE - (undocumented, for test) set to enable verbose debug # (1=stderr, 2=syslog, 3=ha_log) PATH=/bin:/usr/sbin:$PATH export PM_VERBOSE=${PM_VERBOSE:-0} # Logging disabled by default export pm=${PM_OVERRIDE:-pm -h $serverhost} pmlog () { case "$PM_VERBOSE" in 1) echo "powerman-stonith: $*" >&2 ;; 2) logger -t heartbeat "powerman-stonith: $*" ;; 3) ha_logger -t heartbeat "powerman-stonith: $*" ;; esac } # N.B. agent must not exit 0 if the target is still on! (chaos bz 1439) # Heartbeat will retry if we fail (don't retry here) pmoff () { local plug=$1 local state rc $pm -0 $plug rc=$? pmlog "$pm -0 $plug, rc=$rc" if [ $rc == 0 ]; then # for multi-plug aliases, all must be off (jira TOSS-1962) for state in $($pm -qx $plug | awk '{ print $NF }'); do if [ "$state" != "off" ]; then state="unknown" rc=1 break; fi done pmlog "$pm -q $plug, state=$state, rc=$rc" fi return $rc # 0=success } pmon () { local plug=$1 local rc $pm -1 $plug rc=$? pmlog "$pm -1 $plug, rc=$rc" return $rc # 0=success } pmcycle () { local plug=$1 local rc $pm -c $plug rc=$? pmlog "$pm -c $plug, rc=$rc" return $rc # 0=success } case $1 in gethosts) exec $pm -lx ;; on) pmon $2 exit $? ;; off) pmoff $2 exit $? ;; reset) if [ "$poweroff" == "1" ]; then pmoff $2 exit $? else pmcycle $2 exit $? fi ;; status) exec $pm -l >/dev/null ;; getconfignames) echo serverhost echo poweroff exit 0 ;; getinfo-devid|getinfo-devname|getinfo-devdescr) echo "powerman STONITH device" exit 0 ;; getinfo-devurl) echo "http://github.com/chaos/powerman" exit 0 ;; getinfo-xml) cat < host:port of powerman server Specify the host:port of the powerman server, e.g. pmserver:10101 Power off when given reset command For V1 heartbeat which always resets to fence, power off when given the reset command. PMEOL exit 0 ;; *) exit 1 ;; esac powerman-2.4.4/man/000077500000000000000000000000001467035776500141505ustar00rootroot00000000000000powerman-2.4.4/man/Makefile.am000066400000000000000000000005241467035776500162050ustar00rootroot00000000000000man1_MANS = powerman.1 pm.1 man3_MANS = libpowerman.3 man5_MANS = powerman.conf.5 powerman.dev.5 man8_MANS = powermand.8 httppower.8 redfishpower.8 plmpower.8 pm.1: powerman.1 cp powerman.1 $@ CLEANFILES = pm.1 EXTRA_DIST = \ powerman.1 \ libpowerman.3 \ powerman.conf.5 \ powerman.dev.5 \ powermand.8 \ httppower.8 \ plmpower.8 powerman-2.4.4/man/httppower.8.in000066400000000000000000000041521467035776500167040ustar00rootroot00000000000000.TH httppower 8 "1 December 2008" "@PACKAGE_NAME@-@PACKAGE_VERSION@" .SH NAME httppower \- communicate with HTTP based power distribution units .SH SYNOPSIS .B httppower .I "[--url URL] [--header string] [--cookies] [--verbose]" .LP .SH DESCRIPTION .B httppower is a helper program for .B powerman which enables it to communicate with HTTP based power distribution units. It is run interactively by the powerman daemon. .SH OPTIONS .TP .I "-u, --url URL" Set the base URL. .TP .I "-H, --header string" Set extra HEADER to use. .TP .I "-c, --cookies" Enable cookies in session. .TP .I "-v, --verbose" Increase output verbosity. .SH INTERACTIVE COMMANDS The following commands are accepted at the httppower> prompt: .TP .I "auth user:pass" Authenticate to the base URL with specified user and password, using ``basic'' HTTP authentication which sends the user and password over the network in plain text. .TP .I "seturl URL" Set the base URL. Overrides the command line option. .TP .I "setheader [string data]" Set extra HEADER to use. Do not specify data to clear. Overrides the command line option. .TP .I "cookies " Enable or disable use of cookies. Overrides the command line option. .TP .I "get [URL-suffix]" Send an HTTP GET to the base URL with the optional URL-suffix appended. .TP .I "post [URL-suffix] " Send an HTTP POST to the base URL with the optional URL-suffix appended, and string data as argument. Typically, the data is key=value pairs (multiple of which can be concatenated with the &-symbol), but there can be exceptions. .TP .I "put [URL-suffix] " Send an HTTP PUT to the base URL with the optional URL-suffix appended, and string data as argument. .SH "FILES" @X_SBINDIR@/httppower .br @X_SYSCONFDIR@/powerman/powerman.conf .SH "ORIGIN" PowerMan was originally developed by Andrew Uselton on LLNL's Linux clusters. This software is open source and distributed under the terms of the GNU GPL. .SH "SEE ALSO" .BR powerman (1), .BR powermand (8), .BR httppower (8), .BR plmpower (8), .BR vpcd (8), .BR powerman.conf (5), .BR powerman.dev (5). .PP \fBhttp://github.com/chaos/powerman\fR powerman-2.4.4/man/libpowerman.3.in000066400000000000000000000126471467035776500171720ustar00rootroot00000000000000.TH libpowerman 3 "2 December 2008" "@PACKAGE_NAME@-@PACKAGE_VERSION@" .SH NAME libpowerman \- PowerMan Client API .SH SYNOPSIS .nf .B #include .sp .BI "pm_err_t pm_connect (char *" server ", void *" arg ", pm_handle_t *" hp , .BI " int " flags ); .sp .BI "void pm_disconnect (pm_handle_t " h ); .sp .BI "pm_err_t pm_node_on (pm_handle_t " h ", char *" node ); .sp .BI "pm_err_t pm_node_off (pm_handle_t " h ", char *" node ); .sp .BI "pm_err_t pm_node_cycle (pm_handle_t " h ", char *" node ); .sp .BI "pm_err_t pm_node_status (pm_handle_t " h ", char *" node , .BI " pm_node_state_t " sp ); .sp .BI "pm_err_t pm_node_iterator_create (pm_handle_t " h , .BI " pm_node_iterator_t *" ip ); .sp .BI "void pm_node_iterator_destroy (pm_node_iterator_t " i ); .sp .BI "char * pm_node_next (pm_node_iterator_t " i ); .sp .BI "void pm_node_iterator_reset (pm_node_iterator_t " i ); .sp .BI "char * pm_strerror (pm_err_t " err ", char * " str ", int " len ); .sp .B cc ... -lpowerman .fi .SH DESCRIPTION The \fBpm_connect\fR() function establishes a connection with \fIserver\fR, a string containing \fIhost[:port]\fR or NULL for defaults; and returns a handle in \fIhp\fR. The \fIarg\fR parameter is currently unused. The \fIflags\fR parameter should be zero or one or more logically-OR'ed flags: .TP .B PM_CONN_INET6 Establish connection to the powerman server using (only) IPv6 protocol. Without this flag, any available address family will be used. .PP The \fBpm_disconnect\fR() function tears down the server connection and frees storage associated with handle \fIh\fR. .PP The \fBpm_node_on\fR(), \fBpm_node_off\fR(), and \fBpm_node_cycle\fR() functions issue on, off, and cycle commands acting on \fInode\fR to the server on handle \fIh\fR. .PP The \fBpm_node_status\fR() function issues a status query acting on \fInode\fR to the server on handle \fIh\fR. The result is resturned in \fIsp\fR which will be one of the values: .TP .B PM_ON Node is powered on. .TP .B PM_OFF Node is powered off. .TP .B PM_UNKNOWN Node state is unknown. Some devices may return this even when the query is successful, for example X10 devices controlled by \fBplmpower\fR. .PP To use the above functions you must know the name of the node you wish to control. Calling \fBpm_node_iterator_create\fR() on handle \fIh\fR returns an iterator \fIip\fR which can be used to walk the list of valid node names. \fBpm_node_next\fR() returns the next node in the list, or NULL when the end of the list is reached. \fBpm_node_iterator_reset\fR() rewinds iterator \fIi\fR to the beginning of the list. Finally, \fBpm_node_iterator_destroy\fR() destroys an iterator and reclaims its storage. .SH RETURN VALUE Most functions have a return type of \fIpm_err_t\fR. \fBpm_strerror\fR() is available to convert an error code \fIerr\fR to a human-readable string using storage \fIstr\fR of length \fIlen\fR passed in by the caller. .SH ERRORS .TP .B PM_ESUCCESS Success. .TP .B PM_ERRNOVALID System call failed, see system errno. .TP .B PM_ENOADDR Failed to get address info for server. .TP .B PM_ECONNECT Connect failed. .TP .B PM_ENOMEM Out of memory. .TP .B PM_EBADHAND Bad server handle. .TP .B PM_EBADARG Bad argument. .TP .B PM_ESERVEREOF Received unexpected EOF from server. .TP .B PM_ESERVERPARSE Received unexpected response from server. .TP .B PM_EUNKNOWN Server responded with ``unknown command''. .TP .B PM_EPARSE Server responded with ``parse error''. .TP .B PM_ETOOLONG Server responded with ``command too long''. .TP .B PM_EINTERNAL Server responded with ``internal error''. .TP .B PM_EHOSTLIST Server responded with ``hostlist error''. .TP .B PM_EINPROGRESS Server responded with ``command in progress''. .TP .B PM_ENOSUCHNODES Server responded with ``no such nodes''. .TP .B PM_ECOMMAND Server responded with ``command completed with errors''. .TP .B PM_EQUERY Server responded with ``query completed with errors''. .TP .B PM_EUNIMPL Server responded with ``not implemented by device''. .SH EXAMPLE This example program queries the list of valid nodes and turns them all on. .PP .nf #include #include #include .sp int main(int argc, char *argv[]) { pm_err_t err; pm_node_state_t s; pm_handle_t h; pm_node_iterator_t i; char ebuf[64], *node; .sp if ((err = pm_connect (NULL, NULL, &h, 0)) != PM_ESUCCESS) { fprintf (stderr, "pm_connect: %s\\n", pm_strerror (err, ebuf, sizeof (ebuf))); exit(1); } .sp if ((err = pm_node_iterator_create (h, &i)) != PM_ESUCCESS) { fprintf (stderr, "pm_node_iterator_create: %s\\n", pm_strerror (err, ebuf, sizeof (ebuf))); exit(1); } while ((node = pm_node_next (i))) { if ((err = pm_node_on (h, node)) != PM_ESUCCESS) { fprintf (stderr, "pm_node_on: %s\\n", pm_strerror (err, ebuf, sizeof(ebuf))); exit (1); } } pm_node_iterator_destroy (i); .sp pm_disconnect (h); exit (0); } .fi .SH "FILES" @X_LIBDIR@/libpowerman.* .br @X_INCLUDEDIR@/libpowerman.h .SH "ORIGIN" PowerMan was originally developed by Andrew Uselton on LLNL's Linux clusters. This software is open source and distributed under the terms of the GNU GPL. .SH "SEE ALSO" .BR powerman (1), .BR powermand (8), .BR httppower (8), .BR plmpower (8), .BR vpcd (8), .BR powerman.conf (5), .BR powerman.dev (5). .PP \fBhttp://github.com/chaos/powerman\fR powerman-2.4.4/man/plmpower.8.in000066400000000000000000000050131467035776500165120ustar00rootroot00000000000000.TH plmpower 8 "1 December 2008" "@PACKAGE_NAME@-@PACKAGE_VERSION@" .SH NAME plmpower \- control Insteon/X10 devices via SmartLabs PLM 2412S .SH SYNOPSIS .B plmpower .I "--device serial-port" .LP .SH DESCRIPTION .B plmpower is a helper program for .B powerman which enables communication with Insteon/X10 devices via SmartLabs Power Line Modem, model 2412S. It is run interactively by the powerman daemon. It can also be useful as a standalone tool for debugging X10/Insteon networks based on the above device. .SH NETWORK SETUP Note the addresses of your Insteon/X10 devices. Plug the PLM into an AC outlet, preferably on the same electrical phase as the devices under control. Devices are available to bridge phases if this is not possible. .LP Attach the PLM's serial port to your computer, and ensure that nothing else is using the serial port such as the system console or getty(8). Run .B plmpower and try the interactive commands below to see if the devices respond reliably. .LP Once everything is working, configure .B powermand to run .B plmpower as a coprocess as described in powerman.conf(5). .SH OPTIONS .TP .I "-d, --device serial-port" Specify the path to the special file connected to the PLM's serial port. .TP .I "-t, --timeout msec" Set the Insteon timeout to the specified number of milliseconds (default 1000). .TP .I "-x, --x10-attempts number" Set the number of times to run every X10 command (default 3). X10 does not provide an ACK/NAK mechanism like Insteon so we cannot be certain that any particular X10 command completed, therefore X10 commands are issued multiple times to increase confidence. .SH INTERACTIVE COMMANDS The following commands are accepted at the plmpower> prompt. Address arguments may be Insteon (e.g. 1A.2B.3C) or X10 (e.g. G12). .TP .I "help" Display help on the available commands. .TP .I "info" Get info about the PLM. .TP .I "reset" Reset the PLM (clears the all-link db). .TP .I "on addr" Turn on device. .TP .I "off addr" Turn off device. .TP .I "status addr" Query status of device (Insteon only). .TP .I "ping addr" Time round trip request/response to device (Insteon only). .SH "FILES" @X_SBINDIR@/plmpower .br @X_SYSCONFDIR@/powerman/powerman.conf .SH "ORIGIN" PowerMan was originally developed by Andrew Uselton on LLNL's Linux clusters. This software is open source and distributed under the terms of the GNU GPL. .SH "SEE ALSO" .BR powerman (1), .BR powermand (8), .BR httppower (8), .BR plmpower (8), .BR vpcd (8), .BR powerman.conf (5), .BR powerman.dev (5). .PP \fBhttp://github.com/chaos/powerman\fR powerman-2.4.4/man/powerman.1.in000066400000000000000000000103351467035776500164710ustar00rootroot00000000000000.TH powerman 1 "1 December 2008" "@PACKAGE_NAME@-@PACKAGE_VERSION@" .SH NAME powerman \- power on/off nodes .SH SYNOPSIS .B pm .I "[OPTIONS] [ACTION [TARGETS ...]]" .SH DESCRIPTION .B powerman provides power management in a data center or compute cluster environment. It performs operations such as power on, power off, and power cycle via remote power controller devices. Target hostnames are mapped to plugs on devices in .I powerman.conf(5). .SH ACTIONS .TP .I "-1, --on" Power ON targets. .TP .I "-0, --off" Power OFF targets. .TP .I "-c, --cycle" Power cycle targets. .TP .I "-q, --query" Query plug status of targets, if specified, or all targets if not. Status is not cached; each time this option is used, powermand queries the appropriate devices. Targets connected to devices that could not be contacted (e.g. due to network failure) or had some other type of error or are reported as status "unknown". If possible, output will be compressed into host ranges. .TP .I "-l, --list" List available targets. If possible, output will be compressed into a host range (see TARGET SPECIFICATION below). .TP .I "-r, --reset" Assert hardware reset for targets. .TP .I "-f, --flash" Turn beacon ON for targets. .TP .I "-u, --unflash" Turn beacon OFF for targets. .TP .I "-B, --beacon" Query beacon status of targets, if specified, or all targets if not. .TP .I "-t, --temp" Query node temperature of targets, if specified, or all targets if not. Temperature information is not interpreted by powerman and is reported as received from the device on one line per target, prefixed by target name. .SH OPTIONS .TP .I "-h, --server-host host[:port]" Connect to a powerman daemon on non-default host and optionally port. .TP .I "-x, --exprange" Expand host ranges in query responses. .TP .I "-V, --version" Display the powerman version number and exit. .TP .I "-L, --license" Show powerman license information. .TP .I "-H, --help" Show command usage. .TP .I "-g, --genders" Interpret targets as genders attributes rather than node names. Each attribute is expanded to the list of nodes that have that attribute, then those lists are combined to make a list of target node names. .SH TEST/DEBUG OPTIONS The following options may be helpful in the test environment or when debugging device scripts. .TP .I "-T, --telemetry" Causes device telemetry information to be displayed as commands are processed. Useful for debugging device scripts. .TP .I "-R, --retry-connect N" Retry connect to server up to N times with a 100ms delay after each failure. .TP .I "-d, --device" Displays device status information for the device(s) that control the targets, if specified, or all devices if not. .SH "TARGET SPECIFICATION" .B powerman target hostnames may be specified as comma separated or space separated hostnames or host ranges. Host ranges are of the general form: prefix[n-m,l-k,...], where n < m and l < k, etc., This form should not be confused with regular expression character classes (also denoted by ``[]''). For example, foo[19] does not represent foo1 or foo9, but rather represents a degenerate range: foo19. .LP This range syntax is meant only as a convenience on clusters with a prefixNN naming convention and specification of ranges should not be considered necessary -- the list foo1,foo9 could be specified as such, or by the range foo[1,9]. .LP Some examples of powerman targets follows: .LP Power on hosts bar,baz,foo01,foo02,...,foo05 powerman --on bar baz foo[01-05] .LP Power on hosts bar,foo7,foo9,foo10 powerman --on bar,foo[7,9-10] .LP Power on foo0,foo4,foo5 powerman --on foo[0,4-5] .LP As a reminder to the reader, some shells will interpret brackets ([ and ]) for pattern matching. Depending on your shell, it may be necessary to enclose ranged lists within quotes. For example, in tcsh, the last example above should be executed as: .nf powerman --on "foo[0,4-5]" .fi .SH "FILES" @X_BINDIR@/powerman .br @X_BINDIR@/pm .SH "ORIGIN" PowerMan was originally developed by Andrew Uselton on LLNL's Linux clusters. This software is open source and distributed under the terms of the GNU GPL. .SH "SEE ALSO" .BR powerman (1), .BR powermand (8), .BR httppower (8), .BR plmpower (8), .BR vpcd (8), .BR powerman.conf (5), .BR powerman.dev (5). .PP \fBhttp://github.com/chaos/powerman\fR powerman-2.4.4/man/powerman.conf.5.in000066400000000000000000000050351467035776500174220ustar00rootroot00000000000000.TH powerman.conf 5 "13 January 2012" "@PACKAGE_NAME@-@PACKAGE_VERSION@" .SH NAME powerman.conf \- configuration file for PowerMan .SH DESCRIPTION The powerman.conf file typically includes one or more of the remote power controller (RPC) device files provided in the /etc/powerman directory; sets a few global options; instantiates RPC devices with unique names, hostnames, and ports; and maps node names to RPC's and plug numbers. .LP Network-attached RPC's are instantiated with device lines of the form: .IP device "name" "type" "host:port" .LP Serial-attached RPC's are instantiated with device lines of the form: .IP device "name" "type" "special file" "flags" .LP where special file is the full path to a tty device, and flags is a serial parameter specification in a form similar to that used by lilo, e.g. "9600,8n1". RPC's that are accessed via coprocesses are instantiated as follows: .IP device "name" "type" "process |&" .LP where process is the full path to a process whose standard output and input will be controlled by powerman, e.g. "/usr/bin/conman -Q -j rpc0 |&". .SH EXAMPLE The following example is a 16-node cluster that uses two 8-plug Baytech RPC-3 remote power controllers. .LP .nf include "/etc/powerman/baytech.dev" # include def for "baytech" RPC tcpwrappers yes # enable TCP wrappers # listen "0.0.0.0:10101" # uncomment to listen on all interfaces # plug_log_level "info" # uncomment to change syslog messages # for plug state changes to level # info (default level is debug) # Alias example - alias can be used in target specifications alias "pengra_service" "pengra[0-1]" alias "pengra_compute" "pengra[2-15]" # Power controller: device [] device "pow0" "baytech" "pow0:23" # instantiate pow0 device "pow1" "baytech" "pow1:23" # instantiate pow1 # Plugs: node [] node "pengra[0-7]" "pow0" "[1-8]" # map pengra0...pengra7 to pow0 plug 1-8 node "pengra[8-15]" "pow1" "[1-8]" # map pengra8...pengra15 to pow1 plug 1-8 .fi .SH "FILES" @X_SYSCONFDIR@/powerman/powerman.conf .br @X_SYSCONFDIR@/powerman/*.dev .SH "ORIGIN" PowerMan was originally developed by Andrew Uselton on LLNL's Linux clusters. This software is open source and distributed under the terms of the GNU GPL. .SH "SEE ALSO" .BR powerman (1), .BR powermand (8), .BR httppower (8), .BR plmpower (8), .BR vpcd (8), .BR powerman.conf (5), .BR powerman.dev (5). .PP \fBhttp://github.com/chaos/powerman\fR powerman-2.4.4/man/powerman.dev.5.in000066400000000000000000000203431467035776500172520ustar00rootroot00000000000000.TH powerman.dev 5 "13 January 2012" "@PACKAGE_NAME@-@PACKAGE_VERSION@" .SH NAME powerman.dev \- PowerMan device specification files .SH DESCRIPTION PowerMan device specifications are rather weird. For this reason, we suggest that you leave the writing of these scripts to the PowerMan authors. However, if you insist, here is how they work. .LP Note: the authors do not guarantee that the PowerMan specification language will not change, however we are open to taking on maintenance of scripts submitted by PowerMan users. We can't guarantee that we'll be able to test new releases against all devices but we'll do our best not to break anything. NOTE: the best way to help us in this endeavor is to provide a ``simulator'' for your power controller and associated tests in the \fItest\fR subdirectory of the powerman source code. See the examples in that directory. .LP By convention, device scripts are one device per file and are included as needed from a powerman.conf file, like this: .IP .nf include "/etc/powerman/icebox3.dev" .fi .LP A device script is surrounded by an outer block: .IP .nf specification "my_device_name" { # configuration settings # script blocks } .fi .LP The possible configuration settings are: .TP .I "timeout " (optional) device script timeout in seconds - applies to each script, the whole thing, not just a particular "expect". .TP .I "plug name { }" (optional) if plug names are static, they should be defined. Any reference to a plug name in the powerman.conf must match one of the defined plug names. .TP .I "pingperiod " (optional) if a ping script is defined, and pingperiod is nonzero, the ping script will be executed periodically, every seconds. .LP Script blocks have the form: .IP .nf script { # statements } .fi .LP Script blocks should all be grouped together with no config lines in between. Scripts are for performing particular operations such as power on, get power status, etc. The various script names are listed below. Those marked with [%s] are called with a plug name "argument", which can be included in a send statements by including a %s (printf style). Warning: all the send strings are processed with printf and you can cause powermand to segfault if you include any printf tokens other than the appropriate zero or one %s. .TP .I "login" Executed immediately on (re-)connect. If you need to login to the box, do it here. This is also a good place to descend through a first layer of menus. Caveat: % occurring in passwords must be escaped as %%. Caveat: occurs outside of client session so cannot be debugged with -T. A trick when debugging is to move this code into the status script temporarily so you can see what is going on. .TP .I "logout" Executed prior to disconnect. Get device in a state so login script will work (though hopefully disconnecting will do that too). .TP .I "status_all, status[%s]" Obtain plug state for all plugs or only the specified plug. In most cases, only one script needs to be specified. In some hardware where unpopulated plugs may be problematic, it may be beneficial to specify both. If both scripts are specified, the status_all script will be called only when all plug are requested. .TP .I "on_all, on_ranged[%s], on[%s]" Power on all plugs, a range of plugs, or the specified plug. .TP .I "off_all, off_ranged[%s], off[%s]" Power off all plugs, a range of plugs, or the specified plug. .TP .I "cycle_all, cycle_ranged[%s], cycle[%s]" Power cycle all plugs, a range of plugs, or the specified plug. The intent of this command was to map to the RPC's cycle command; however, device script are increasingly implementing this in terms of a power off/delay/power so the off time can be controlled by the script. .TP .I "status_soft_all, status_soft[%s]" Obtain soft power state for all plugs or only the specified plug. Soft Power refers to the "standby state" of the node. On means the node is powered up. Off means either the node is powered off at the plug or is powered on at the plug and in standby mode. This is really only useful on devices that include both a plug relay and a probe into the node attached to a non-standby power source. .TP .I "status_temp_all, status_temp[%s]" Obtain temperature reading for all plugs or only the specified plug. Temperature is obtained by sampling a thermocouple in the node. Results are reported as a text string - not interpreted by Powerman beyond any regex chopping done by the script. In most cases, only one script needs to be specified. In some hardware where unpopulated plugs may be problematic, it may be beneficial to specify both. If both scripts are specified, the status_all script will be called only when all plug are requested. .TP .I "status_beacon_all, status_beacon[%s]" Obtain beacon state for all plugs or only the specified plug. Some RPC's include a way to flash a light on a node. In most cases, only one script needs to be specified. In some hardware where unpopulated plugs may be problematic, it may be beneficial to specify both. If both scripts are specified, the status_all script will be called only when all plugs are requested. .TP .I "beacon_on[%s]" Flash beacon on the specified plug. .TP .I "beacon_off[%s]" Clear beacon on the specified plug. .TP .I "reset_all, reset_ranged[%s], reset[%s]" Reset all plugs, a range of plugs, or only the specified plug. Reset refers to signaling a motherboard reset butten header, not a plug cycle. .LP Within a script, the following statements can be used: .TP .I "send " Send to the device. .TP .I "delay " Pause script for seconds. .TP .I "expect " is compiled as a regular expression with regcomp(3). The regular expression is matched against device input. The script blocks until the regex is matched or the device timeout occurs (in which case the script is aborted). Upon matching, any parenthesized expressiones are assigned to variables: $1 for the first match, $2 for the second match, and so on. Warning: some implementations of regex(3) silently fail if the regular expression exceeds available static storage. .TP .I "setplugstate [|] [off=] [on=]" Set the plug state. The first argument, if present, is the literal plug name or a from the previous expect which contains the plug name. If omitted, the plug name is presumed to be the script argument. The off and on strings are compiled regexes, which if matched by the second argument, result in the plug state being set to off or on. Yes we are applying regexes to regmatches! If no off or on strings are provided, state will be unknown. .TP .I "setresult success=" Set the result state. The first argument, a from the previous expect which contains the plug name. The success string is a compiled regex, which if it matches the second argument, results in the power operation being successful for this plug. .TP .I "ifoff, ifon" Script statements enclosed in an ifon/ifoff block are conditional executed based on the state of the plug passed in as an argument. Ifon/ifoff blocks can only be used in single plug scripts that take an argument. .TP .I "foreachplug" Script statements enclosed in a foreachplug block are executed iteratively with a %s argument defined for each target plug. Foreachplug blocks can only be used in all plug scripts that take no argument. .LP Script terminals are defined as follows: .TP .I "" decimal number - exponent forms not supported .TP .I "" Text surrounded by double quotes. May contain C style backslash-escaped characters, including three digit octal values, and most common backslash-escaped single character values. .TP .I "" Multiple values separated by white space. .TP .I "" Name of script (see above). .TP .I "" Results of a parenthesized regular expression match are assigned to $1, $2, ... $N. .SH "FILES" @X_SYSCONFDIR@/powerman/*.dev .SH "ORIGIN" PowerMan was originally developed by Andrew Uselton on LLNL's Linux clusters. This software is open source and distributed under the terms of the GNU GPL. .SH "SEE ALSO" .BR powerman (1), .BR powermand (8), .BR httppower (8), .BR plmpower (8), .BR vpcd (8), .BR powerman.conf (5), .BR powerman.dev (5). .PP \fBhttp://github.com/chaos/powerman\fR powerman-2.4.4/man/powermand.8.in000066400000000000000000000026251467035776500166470ustar00rootroot00000000000000.TH powermand 8 "13 January 2012" "@PACKAGE_NAME@-@PACKAGE_VERSION@" .SH NAME powermand \- power control and monitoring daemon .SH SYNOPSIS .B powermand .I "[-options]" .LP .SH DESCRIPTION .B powermand provides power management in a data center or compute cluster environment. .SH OPTIONS .TP .I "-c, --conf filename" Override the default location of the powerman configuration file .I /etc/powerman/powerman.conf. .TP .I "-s, --stdio" Talk to a client on stdin/stdout rather than listening for network connections. This is useful for testing new configurations, since the powerman client protocol is friendly to humans. .TP .I "-Y, --short-circuit-delay" Ignore all device script delay statements. This is useful for testing with simulated devices, where the delays slow down testing for no benefit. .TP .I "-d, --debug mask" Set mask for debugging output. .TP .I "-h, --help" Provide a synopsis of the command options. .TP .I "-V, --version" Display the powerman version number and exit. .SH "FILES" @X_SBINDIR@/powermand .br @X_SYSCONFDIR@/powerman/powerman.conf .SH "ORIGIN" PowerMan was originally developed by Andrew Uselton on LLNL's Linux clusters. This software is open source and distributed under the terms of the GNU GPL. .SH "SEE ALSO" .BR powerman (1), .BR powermand (8), .BR httppower (8), .BR plmpower (8), .BR vpcd (8), .BR powerman.conf (5), .BR powerman.dev (5). .PP \fBhttp://github.com/chaos/powerman\fR powerman-2.4.4/man/redfishpower.8.in000066400000000000000000000211511467035776500173470ustar00rootroot00000000000000.TH redfishpower 8 "1 October 2021" "@PACKAGE_NAME@-@PACKAGE_VERSION@" .SH NAME redfishpower \- communicate with redfish service processors in parallel .SH SYNOPSIS .B redfishpower .I "<--hostname hostname(s) | --hostsfile file> [OPTIONS]" .LP .SH DESCRIPTION .B redfishpower is a helper program for .B powerman which enables it to communicate with redfish service processors in parallel. It is run interactively by the powerman daemon. .SH OPTIONS .TP .I "-h, --hostname hostname(s)" Set legal hostnames that redfishpower can communicate with. Host ranges are acceptable. Note that the maximum number of hosts that can be set simultaneously is limited by the file descriptor limit of the .B select(2) system call. .TP .I "-H, --header string" Set extra HEADER to use. Typically is Content-Type:application/json. .TP .I "-A, --auth user:pass" Authenticate with the specified user and password, specified in the form "user:pass". If specified on the command line, it cannot be set at the prompt with the "auth" command. .TP .I "-S, --statpath string" Set Redfish path for obtaining power status. Typically is redfish/v1/Systems/1. .TP .I "-O, --onpath string" Set default Redfish path for performing power on. Typically is redfish/v1/Systems/1/Actions/ComputerSystem.Reset. .TP .I "-F, --offpath string" Set default Redfish path for performing power off. Typically is redfish/v1/Systems/1/Actions/ComputerSystem.Reset. .TP .I "-P, --onpostdata string" Set default Redfish postdata for performing power on. Typically is {"ResetType":"On"} .TP .I "-G, --offpostdata string" Set default Redfish postdata for performing power off. Typically is {"ResetType":"ForceOff"} .TP .I "-m, --message-timeout seconds" Set message timeout, the timeout most notably associated with connection timeouts or name resolution timeouts. Default is 10 seconds. Note that this different than the command timeout specified by .B settimeout below. The latter is the total command timeout, which may involve multiple messages and a polling of power status. .TP .I "-o, --resolve-hosts" Resolve host and pass IP address to libcurl instead of hostname. This works around a DNS race in libcurl versions less than 7.66. Users hitting the DNS race may see "Timeout was reached" errors. Note that all resolved host lookups will be permanently cached, it is assumed the IP address of hosts will never change. .TP .I "-v, --verbose" Increase output verbosity. Can be specified multiple times. .SH INTERACTIVE COMMANDS The following commands are accepted at the redfishpower> prompt: .TP .I "auth user:pass" Authenticate to the base URL with specified user and password, using ``basic'' HTTP authentication which sends the user and password over the network in plain text. .TP .I "setheader [string data]" Set extra HEADER to use. Do not specify data to clear. .TP .I "setstatpath " Set default path to obtain power status. .TP .I "setonpath [postdata]" Set default path and optional post data to turn on plug. .TP .I "setoffpath [postdata]" Set default path and optional post data to turn off plug. .TP .I "setplugs plugnames hostindices [parentplug]" Associate a plug name with one of the hostnames specified on the command line, referred to by its zero origin index. Optionally set a parent to the plug, which must have its power status queried first. See HIERARCHY CONFIGURATION below for more details. Can be called multiple times to configure all possible plugs. In most cases the number of plugs should equal the number of indices. Multiple plugs can be mapped to a single host index, which is typically used along with plug substitution (see "setpath" command below). .TP .I "setpath [postdata]" Set path for specific plug power command ("stat", "on", "off") and optional post data. The plug name can be substituted into the URI path by specifying "{{plug}}" in the path. .TP .I "settimeout " Set command timeout in seconds. .TP .I "stat [plugs]" Get power status of all plugs or specified subset of plugs. .TP .I "on [plugs]" Turn on all plugs or specified subset of plugs. Will return "ok" after confirmation "on" has completed. .TP .I "off [plugs]" Turn off all plugs or specified subset of plugs. Will return "ok" after confirmation "off" has completed. .SH "UPDATING REDFISHPOWER DEVICE FILES" .LP Users may often need to modify .B redfishpower device files for other systems, as URI paths may be slightly different. .LP To find the URI paths on your system, a good starting point is to use .B curl(1) to discover the correct paths at the following standard location. Note that the output can be easier to read if piped to .B jq(1), but that is optional. .PP .B # curl -s -u USER:PASS -k -X GET https:///redfish/v1/Systems | jq .LP Information in the response will point you on how to dig further. Several paths the authors have seen include: .PP .B # curl -s -u USER:PASS -k -X GET https:///redfish/v1/Systems/1 .PP .B # curl -s -u USER:PASS -k -X GET https:///redfish/v1/Systems/Node0 .PP .B # curl -s -u USER:PASS -k -X GET https:///redfish/v1/Systems/Self .LP Internally within .B redfishpower, an \fIon\fR or \fIoff\fR command will not return until the \fIon\fR/\fIoff\fR is confirmed to complete. i.e. \fIstat\fR returns the expected status. .LP This can sometimes take awhile and on some systems may push the timeout limit specified in the device file (typically 60 seconds). If necessary, it should be increased at the top of the specification file (via \fItimeout\fR) and the login section of device file (via \fIsettimeout\fR). .LP Note that the .B powerman timeout should account for the combined time of an \fIoff\fR and \fIon\fR for the \fIcycle\fR operation. .SH "HIERARCHY CONFIGURATION" Users of .B redfishpower can configure power control dependencies within the hosts specified on the command line. This is typically necessary for bladed environments where a chassis must be powered on before any power control operations can be done on a blade. .B For example, assume a chassis that has two blades, and each blade has two nodes underneath it. These hosts might be configured via the .I --hostnames option like .B "--hostnames chassis,blades[0-1],nodes[0-3]". .LP The power control dependency hierarchy could be configured in .B redfishpower via: .PP .nf script login { send "setplugs Root 0\\n" expect "redfishpower> " send "setplugs Parent[0-1] [1-2] Root\\n" expect "redfishpower> " send "setplugs Leaf[0-1] [3-4] Parent0\\n" expect "redfishpower> " send "setplugs Leaf[2-3] [5-6] Parent1\\n" expect "redfishpower> " } .fi .LP In the above example the plugname "Root" is used for the root node (index 0 of configured hosts), "Parent[0-1]" is used for the blades (the indexes 1-2), the nodes are assigned the plugnames "Leaf[0-3]" (index 3-6). "Root" is assigned no parent, "Parent[0-1]" are assigned parent "Root", and leaves are assigned parents of "Parent0" or "Parent1" depending on the node. .LP .B Redfishpower will handle the following when dealing with power control dependencies: .LP When checking power status, the status of a parents/ancestors will always be checked first. If an ancestor is "off", "unknown", or "error", all descendants will be defined as "off", "unknown", or "error" respectively. If all ancestors are "on", the power status of the targeted children can be checked accordingly. .LP When powering on, the status of parents/ancestors will be checked first. If an ancestor is not "on", descendants cannot be powered on and an appropriate message is output as a result. If all ancestors are "on", the power on to the child can be completed. .LP When powering off, the status of parents/ancestors will be checked first. If all ancestors are "on", the power off to the child can be completed. If any ancestor is "off", the power off is assumed to be successful. .LP Note that .B redfishpower does not allow both parents and children to be powered on at the same time. This "phased" power on is highly dependent on hardware implementation and has shown itself to be unreliable. However both parents and children can be powered off. When the ancestor completes its power off, it is assumed all children ared powered off as well. .SH "FILES" @X_SBINDIR@/redfishpower .br @X_SYSCONFDIR@/powerman/powerman.conf .SH "ORIGIN" PowerMan was originally developed by Andrew Uselton on LLNL's Linux clusters. This software is open source and distributed under the terms of the GNU GPL. .SH "SEE ALSO" .BR powerman (1), .BR powermand (8), .BR plmpower (8), .BR vpcd (8), .BR powerman.conf (5), .BR powerman.dev (5). .PP \fBhttp://github.com/chaos/powerman\fR powerman-2.4.4/scripts/000077500000000000000000000000001467035776500150645ustar00rootroot00000000000000powerman-2.4.4/scripts/debbuild.sh000077500000000000000000000020211467035776500171700ustar00rootroot00000000000000#!/bin/sh PACKAGE=powerman USER=$(git config --get user.name) DEBFULLNAME=$USER EMAIL=$(git config --get user.email) DEBEMAIL=$EMAIL SRCDIR=${1:-$(pwd)} die() { echo "debbuild: $@" >&2; exit 1; } log() { echo "debbuild: $@"; } test -z "$USER" && die "User name not set in git-config" test -z "$EMAIL" && die "User email not set in git-config" log "Running make dist" make dist >/dev/null || exit 1 log "Building package from latest dist tarball" tarball=$(ls -tr *.tar.gz | tail -1) version=$(echo $tarball | sed "s/${PACKAGE}-\(.*\)\.tar\.gz/\1/") rm -rf debbuild mkdir -p debbuild && cd debbuild mv ../$tarball . log "Unpacking $tarball" tar xvfz $tarball >/dev/null log "Creating debian directory and files" cd ${PACKAGE}-${version} cp -a ${SRCDIR}/debian . || die "failed to copy debian dir" export DEBEMAIL DEBFULLNAME log "Creating debian/changelog" dch --create --package=$PACKAGE --newversion $version build tree release log "Running debian-buildpackage -b" dpkg-buildpackage -b log "Check debbuild directory for results" powerman-2.4.4/scripts/install-deps-deb.sh000077500000000000000000000002261467035776500205520ustar00rootroot00000000000000#!/bin/bash apt install \ autoconf \ automake \ libtool \ make \ bison \ flex \ libsnmp-dev \ libcurl4-gnutls-dev \ libgenders-dev powerman-2.4.4/src/000077500000000000000000000000001467035776500141645ustar00rootroot00000000000000powerman-2.4.4/src/Makefile.am000066400000000000000000000003341467035776500162200ustar00rootroot00000000000000SUBDIRS = \ libtap \ liblsd \ libczmq \ libcommon \ powerman \ plmpower if WITH_HTTPPOWER SUBDIRS += httppower endif if WITH_SNMPPOWER SUBDIRS += snmppower endif if WITH_REDFISHPOWER SUBDIRS += redfishpower endif powerman-2.4.4/src/httppower/000077500000000000000000000000001467035776500162205ustar00rootroot00000000000000powerman-2.4.4/src/httppower/Makefile.am000066400000000000000000000003271467035776500202560ustar00rootroot00000000000000AM_CFLAGS = @WARNING_CFLAGS@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcommon sbin_PROGRAMS = httppower httppower_SOURCES = httppower.c httppower_LDADD = \ $(top_builddir)/src/libcommon/libcommon.la \ $(LIBCURL) powerman-2.4.4/src/httppower/httppower.c000066400000000000000000000213311467035776500204200ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2007 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #if HAVE_CURL_CURL_H #include #else #error httppower needs curl support! #endif #include #include #include #include "xmalloc.h" #include "error.h" #include "argv.h" static char *url = NULL; static char *header = NULL; static struct curl_slist *header_list = NULL; static int cookies = 0; static int verbose = 0; static char *userpwd = NULL; static char errbuf[CURL_ERROR_SIZE]; #define OPTIONS "u:H:cv" static struct option longopts[] = { {"url", required_argument, 0, 'u' }, {"header", required_argument, 0, 'H' }, {"cookies", no_argument, 0, 'c' }, {"verbose", no_argument, 0, 'v' }, {0,0,0,0}, }; void help(void) { printf("Valid commands are:\n"); printf(" auth user:passwd\n"); printf(" seturl url\n"); printf(" setheader string\n"); printf(" cookies \n"); printf(" get [url]\n"); printf(" post [url] \n"); printf(" put [url] \n"); } char * _make_url(char *str) { char *myurl = NULL; if (str && url) { myurl = xmalloc(strlen(url) + strlen(str) + 2); sprintf(myurl, "%s/%s", url, str); } else if (str && !url) { myurl = xstrdup(str); } else if (!str && url) { myurl = xstrdup(url); } return myurl; } void post(CURL *h, char **av) { char *myurl = NULL; char *postdata = NULL; char *url_ptr = NULL; if (av[0] && av[1]) { postdata = xstrdup(av[1]); myurl = _make_url(av[0]); url_ptr = myurl; } else if (av[0]) { postdata = xstrdup(av[0]); url_ptr = url; } if (postdata && url_ptr) { curl_easy_setopt(h, CURLOPT_POST, 1); curl_easy_setopt(h, CURLOPT_URL, url_ptr); curl_easy_setopt(h, CURLOPT_POSTFIELDS, postdata); curl_easy_setopt(h, CURLOPT_POSTFIELDSIZE, strlen (postdata)); if (curl_easy_perform(h) != 0) printf("Error: %s\n", errbuf); curl_easy_setopt(h, CURLOPT_URL, ""); curl_easy_setopt(h, CURLOPT_POSTFIELDS, ""); curl_easy_setopt(h, CURLOPT_POSTFIELDSIZE, 0); } else printf("Nothing to post!\n"); if (myurl) xfree(myurl); if (postdata) xfree(postdata); } struct put_cb_data { char *data; int offset; }; size_t put_read_cb(char *buffer, size_t size, size_t nitems, void *userdata) { struct put_cb_data *pcd = userdata; memcpy (buffer, pcd->data + pcd->offset, size); pcd->offset += size; return size; } void put(CURL *h, char **av) { char *myurl = NULL; char *putdata = NULL; struct put_cb_data pcd; char *url_ptr = NULL; if (av[0] && av[1]) { putdata = xstrdup(av[1]); myurl = _make_url(av[0]); url_ptr = myurl; } else if (av[0]) { putdata = xstrdup(av[0]); url_ptr = url; } if (putdata && url_ptr) { curl_easy_setopt(h, CURLOPT_UPLOAD, 1); curl_easy_setopt(h, CURLOPT_URL, url_ptr); curl_easy_setopt(h, CURLOPT_READFUNCTION, put_read_cb); pcd.data = putdata; pcd.offset = 0; curl_easy_setopt(h, CURLOPT_READDATA, &pcd); curl_easy_setopt(h, CURLOPT_INFILESIZE, strlen (putdata)); if (curl_easy_perform(h) != 0) printf("Error: %s\n", errbuf); curl_easy_setopt(h, CURLOPT_URL, ""); curl_easy_setopt(h, CURLOPT_UPLOAD, 0); } else printf("Nothing to put!\n"); if (myurl) xfree(myurl); if (putdata) xfree(putdata); } void get(CURL *h, char **av) { char *myurl = _make_url(av[0]); if (myurl) { curl_easy_setopt(h, CURLOPT_HTTPGET, 1); curl_easy_setopt(h, CURLOPT_URL, myurl); if (curl_easy_perform(h) != 0) printf("Error: %s\n", errbuf); curl_easy_setopt(h, CURLOPT_URL, ""); } else printf("Nothing to get!\n"); if (myurl) xfree(myurl); } void seturl(CURL *h, char **av) { if (av[0] == NULL) { printf("Usage: seturl http://...\n"); return; } if (url) xfree(url); url = xstrdup(av[0]); } void setheader(CURL *h, char **av) { if (header) { xfree(header); curl_slist_free_all(header_list); header = NULL; header_list = NULL; } if (av[0]) { header = xstrdup(av[0]); header_list = curl_slist_append(header_list, header); curl_easy_setopt(h, CURLOPT_HTTPHEADER, header_list); } else { curl_easy_setopt(h, CURLOPT_HTTPHEADER, header_list); } } void cookies_enable(CURL *h, char **av) { if (av[0] == NULL || (strcasecmp (av[0], "enable") && strcasecmp (av[0], "disable"))) { printf("Usage: cookies \n"); return; } if (!strcasecmp (av[0], "enable")) { /* enable cookie engine with empty string, no need to read from a real file */ curl_easy_setopt(h, CURLOPT_COOKIEFILE, ""); } else { curl_easy_setopt(h, CURLOPT_COOKIELIST, "ALL"); curl_easy_setopt(h, CURLOPT_COOKIEFILE, NULL); } } void auth(CURL *h, char **av) { if (av[0] == NULL) { printf("Usage: auth user:passwd\n"); return; } if (userpwd) xfree(userpwd); userpwd = xstrdup(av[0]); curl_easy_setopt(h, CURLOPT_USERPWD, userpwd); curl_easy_setopt(h, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); } int docmd(CURL *h, char **av) { int rc = 0; if (av[0] != NULL) { if (strcmp(av[0], "help") == 0) help(); else if (strcmp(av[0], "quit") == 0) rc = 1; else if (strcmp(av[0], "auth") == 0) auth(h, av + 1); else if (strcmp(av[0], "seturl") == 0) seturl(h, av + 1); else if (strcmp(av[0], "setheader") == 0) setheader(h, av + 1); else if (strcmp(av[0], "cookies") == 0) cookies_enable(h, av + 1); else if (strcmp(av[0], "get") == 0) get(h, av + 1); else if (strcmp(av[0], "post") == 0) post(h, av + 1); else if (strcmp(av[0], "put") == 0) put(h, av + 1); else printf("type \"help\" for a list of commands\n"); } return rc; } void shell(CURL *h) { char buf[128]; char **av; int rc = 0; while (rc == 0) { printf("httppower> "); fflush(stdout); if (fgets(buf, sizeof(buf), stdin)) { av = argv_create(buf, ""); rc = docmd(h, av); argv_destroy(av); } else rc = 1; } } void usage(void) { fprintf(stderr, "Usage: httppower [--url URL] [--header string] [--cookies]\n"); exit(1); } int main(int argc, char *argv[]) { CURL *h; int c; err_init(basename(argv[0])); while ((c = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != EOF) { switch (c) { case 'u': /* --url */ url = xstrdup(optarg); break; case 'H': /* --header */ header = xstrdup(optarg); break; case 'c': /* --cookies */ cookies = 1; break; case 'v': /* --verbose */ verbose = 1; break; default: usage(); break; } } if (optind < argc) usage(); if (curl_global_init(CURL_GLOBAL_ALL) != 0) err_exit(false, "curl_global_init failed"); if ((h = curl_easy_init()) == NULL) err_exit(false, "curl_easy_init failed"); curl_easy_setopt(h, CURLOPT_TIMEOUT, 5); curl_easy_setopt(h, CURLOPT_ERRORBUFFER, errbuf); curl_easy_setopt(h, CURLOPT_FAILONERROR, 1); /* for time being */ curl_easy_setopt(h, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(h, CURLOPT_SSL_VERIFYHOST, 0L); if (verbose) curl_easy_setopt(h, CURLOPT_VERBOSE, 1L); if (header) { header_list = curl_slist_append(header_list, header); curl_easy_setopt(h, CURLOPT_HTTPHEADER, header_list); } /* enable cookie engine with empty string, no need to read from a real file */ if (cookies) curl_easy_setopt(h, CURLOPT_COOKIEFILE, ""); shell(h); curl_easy_cleanup(h); if (userpwd) xfree(userpwd); if (url) xfree(url); exit(0); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/000077500000000000000000000000001467035776500161435ustar00rootroot00000000000000powerman-2.4.4/src/libcommon/Makefile.am000066400000000000000000000015741467035776500202060ustar00rootroot00000000000000AM_CFLAGS = @WARNING_CFLAGS@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/liblsd noinst_LTLIBRARIES = libcommon.la libcommon_la_SOURCES = \ argv.c \ argv.h \ error.c \ error.h \ fdutil.c \ fdutil.h \ hprintf.c \ hprintf.h \ xmalloc.c \ xmalloc.h \ xpoll.c \ xpoll.h \ xread.c \ xread.h \ xregex.c \ xregex.h \ xsignal.c \ xsignal.h \ xtime.h TESTS = \ test_argv.t \ test_xregex.t check_PROGRAMS = $(TESTS) TEST_EXTENSIONS = .t T_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \ $(top_srcdir)/config/tap-driver.sh test_argv_t_CPPFLAGS = \ -I$(top_srcdir)/src/libtap test_argv_t_SOURCES = test/argv.c test_argv_t_LDADD = \ $(builddir)/libcommon.la \ $(top_builddir)/src/libtap/libtap.la test_xregex_t_CPPFLAGS = \ -I$(top_srcdir)/src/libtap test_xregex_t_SOURCES = test/xregex.c test_xregex_t_LDADD = \ $(builddir)/libcommon.la \ $(top_builddir)/src/libtap/libtap.la powerman-2.4.4/src/libcommon/argv.c000066400000000000000000000047261467035776500172570ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2003 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "xmalloc.h" #include "argv.h" /* make a copy of the first word in str and advance str past it */ static char *_nextargv(char **strp, char *ignore) { char *str = *strp; char *word; int len; char *cpy = NULL; while (*str && (isspace(*str) || strchr(ignore, *str))) str++; word = str; while (*str && !(isspace(*str) || strchr(ignore, *str))) str++; len = str - word; if (len > 0) { cpy = (char *)xmalloc(len + 1); memcpy(cpy, word, len); cpy[len] = '\0'; } *strp = str; return cpy; } /* return number of space separated words in str */ static int _sizeargv(char *str, char *ignore) { int count = 0; do { while (*str && (isspace(*str) || strchr(ignore, *str))) str++; if (*str) count++; while (*str && !(isspace(*str) || strchr(ignore, *str))) str++; } while (*str); return count; } int argv_length(char **argv) { int i = 0; while (argv[i] != NULL) i++; return i; } char **argv_append(char **argv, char *s) { int argc = argv_length(argv) + 1; argv = (char **)xrealloc((char *)argv, sizeof(char *) * (argc + 1)); argv[argc - 1] = xstrdup(s); argv[argc] = NULL; return argv; } /* Create a null-terminated argv array given a command line. * Characters in the 'ignore' set are treated like white space. */ char **argv_create(char *cmdline, char *ignore) { int argc = _sizeargv(cmdline, ignore); char **argv = (char **)xmalloc(sizeof(char *) * (argc + 1)); int i; for (i = 0; i < argc; i++) { argv[i] = _nextargv(&cmdline, ignore); assert(argv[i] != NULL); } argv[i] = NULL; return argv; } /* Destroy a null-terminated argv array. */ void argv_destroy(char **argv) { int i; for (i = 0; argv[i] != NULL; i++) xfree((void *)argv[i]); xfree((void *)argv); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/argv.h000066400000000000000000000017661467035776500172650ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2003 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_ARGV_H #define PM_ARGV_H /* Create a NULL-terminated argv array suitable for passing to execv() * from 'cmdline' string. Characters in the 'ignore' set are treated as white * space. Caller must free with argv_destroy(). */ char **argv_create(char *cmdline, char *ignore); /* Destroy an argv array created by argv_create. */ void argv_destroy(char **argv); /* Return the number of elements in the argv array (less the NULL terminator). */ int argv_length(char **argv); /* Expand an argv array by one slot and add an entry. */ char **argv_append(char **argv, char *s); #endif /* PM_ARGV_H */ powerman-2.4.4/src/libcommon/error.c000066400000000000000000000040421467035776500174400ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include "list.h" #include "error.h" static char *err_prog = NULL; /* basename of calling program */ #define ERROR_BUFLEN 1024 /* * Initialize this module with the name of the program. */ void err_init(char *prog) { char *p = strrchr(prog, '/'); /* store only the basename */ err_prog = p ? p + 1 : prog; } /* helper for err, err_exit */ static void _verr(bool errno_valid, const char *fmt, va_list ap) { char buf[ERROR_BUFLEN]; int er = errno; assert(err_prog != NULL); vsnprintf(buf, ERROR_BUFLEN, fmt, ap); /* overflow ignored on purpose */ if (errno_valid) fprintf(stderr, "%s: %s: %s\n", err_prog, buf, strerror(er)); else fprintf(stderr, "%s: %s\n", err_prog, buf); } /* * Report error message on either stderr or syslog, then exit. */ void err_exit(bool errno_valid, const char *fmt, ...) { va_list ap; va_start(ap, fmt); _verr(errno_valid, fmt, ap); va_end(ap); exit(1); } /* * Report error message on either stderr or syslog, then return. */ void err(bool errno_valid, const char *fmt, ...) { va_list ap; va_start(ap, fmt); _verr(errno_valid, fmt, ap); va_end(ap); } void lsd_fatal_error(char *file, int line, char *mesg) { err_exit(true, "%s", mesg); } void *lsd_nomem_error(char *file, int line, char *mesg) { err_exit(false, "%s: out of memory", mesg); /*NOTREACHED*/ return NULL; } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/error.h000066400000000000000000000015661467035776500174550ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_ERROR_H #define PM_ERROR_H #include #include void err_init(char *prog); void err_exit(bool errno_valid, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); void err(bool errno_valid, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); void lsd_fatal_error(char *file, int line, char *mesg); void *lsd_nomem_error(char *file, int line, char *mesg); #endif /* PM_ERROR_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/fdutil.c000066400000000000000000000020521467035776500175750ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "fdutil.h" #include "error.h" void nonblock_set(int fd) { int flags; flags = fcntl(fd, F_GETFL, 0); if (flags < 0) err_exit(true, "fcntl F_GETFL"); if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) err_exit(true, "fcntl F_SETFL"); } void nonblock_clr(int fd) { int flags; flags = fcntl(fd, F_GETFL, 0); if (flags < 0) err_exit(true, "fcntl F_GETFL"); if (fcntl(fd, F_SETFL, flags & ~(O_NONBLOCK)) < 0) err_exit(true, "fcntl F_SETFL"); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/fdutil.h000066400000000000000000000010671467035776500176070ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_FDUTIL_H #define PM_FDUTIL_H void nonblock_set(int fd); void nonblock_clr(int fd); #endif /* PM_FDUTIL_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/hprintf.c000066400000000000000000000032221467035776500177600ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2003 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include "xmalloc.h" #include "hprintf.h" #include "xread.h" #define CHUNKSIZE 80 char *hvsprintf(const char *fmt, va_list ap) { int len, size = 0; char *str = NULL; do { va_list vacpy; str = (size == 0) ? xmalloc(CHUNKSIZE) : xrealloc(str, size+CHUNKSIZE); size += CHUNKSIZE; va_copy(vacpy, ap); len = vsnprintf(str, size, fmt, vacpy); /* always null terminates */ va_end(vacpy); } while (len == -1 || len >= size); assert(len == strlen(str)); return str; } char *hsprintf(const char *fmt, ...) { char *str; va_list ap; va_start(ap, fmt); str = hvsprintf(fmt, ap); va_end(ap); return str; } int hfdprintf(int fd, const char *format, ...) { char *str, *p; va_list ap; int n, rc; va_start(ap, format); str = hvsprintf(format, ap); va_end(ap); p = str; n = strlen(p); rc = 0; do { rc = xwrite(fd, str, n); if (rc < 0) return rc; n -= rc; p += rc; } while (n > 0); xfree(str); return n; } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/hprintf.h000066400000000000000000000017401467035776500177700ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2003 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_HPRINTF_H #define PM_HPRINTF_H #include /* A vsprintf-like function that allocates the string on the heap and ensures * that no truncation occurs. The caller must Free() the resulting string. */ char *hvsprintf(const char *fmt, va_list ap); /* An sprintf-like function that allocates the string on the heap. * The caller must Free() the resulting string. */ char *hsprintf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); int hfdprintf(int fd, const char *format, ...); #endif /* PM_HPRINTF_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/test/000077500000000000000000000000001467035776500171225ustar00rootroot00000000000000powerman-2.4.4/src/libcommon/test/argv.c000066400000000000000000000032271467035776500202310ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "tap.h" #include "argv.h" int main(int argc, char *argv[]) { char **av; plan(NO_PLAN); av = argv_create("foo bar baz", ""); ok (av != NULL, "argv_create foo bar baz works"); ok (argv_length(av) == 3, "argv_length returns 3"); av = argv_append(av, "bonk"); ok (argv_length(av) == 4, "argv_length returns 4"); is (av[0], "foo", "first arg is foo"); is (av[1], "bar", "second arg is bar"); is (av[2], "baz", "third arg is baz"); is (av[3], "bonk", "fourth arg is bonk"); ok (av[4] == NULL, "vector is NULL terminated"); argv_destroy(av); av = argv_create("a,b:c d", ",:"); ok (av != NULL, "argv_create a,:c d with , and : separators works"); ok (argv_length(av) == 4, "argv_length is 4"); is (av[0], "a", "first arg is a"); is (av[1], "b", "second arg is b"); is (av[2], "c", "third arg is c"); is (av[3], "d", "fourth arg is d"); ok (av[4] == NULL, "vector is null terminated"); argv_destroy(av); done_testing(); exit(0); } // vi:ts=4 sw=4 expandtab powerman-2.4.4/src/libcommon/test/xregex.c000066400000000000000000000151601467035776500205730ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #include #include #include #include #include "tap.h" #include "xregex.h" #include "xmalloc.h" #include "error.h" /* Return true if regex [r] matches exactly [p] in [s]. */ static bool _matchstr(char *r, char *s, char *p) { xregex_t re; xregex_match_t rm; int res; char *tmp; re = xregex_create(); rm = xregex_match_create(2); xregex_compile(re, r, true); res = xregex_exec(re, s, rm); if (res && p) { tmp = xregex_match_strdup(rm); if (strcmp(tmp, p) != 0) res = false; xfree(tmp); } xregex_match_destroy(rm); xregex_destroy(re); return res; } /* Return true if regex [r] matches exactly [s] in [s]. */ static bool _matchstr_all(char *r, char *s) { return _matchstr(r, s, s); } /* Return true if regex [r] matches anything in [s]. */ static bool _match(char *r, char *s) { return _matchstr(r, s, NULL); } static void _check_substr_match(void) { xregex_t re; xregex_match_t rm; char *s; re = xregex_create(); rm = xregex_match_create(2); xregex_compile(re, "foo([0-9]+)bar([0-9]+)", true); ok (xregex_exec(re, "xxxfoo1bar2", rm) == true, "regex with substrings matches xxxfoo1bar2"); s = xregex_match_sub_strdup(rm, 0); ok (s != NULL, "substring 0 matched"); is (s, "foo1bar2", "substring 0 is foo1bar2"); xfree(s); s = xregex_match_sub_strdup(rm, 1); ok (s != NULL, "substring 1 matched"); is (s, "1", "substring 1 is 1"); xfree(s); s = xregex_match_sub_strdup(rm, 2); ok (s != NULL, "substring 2 matched"); is (s, "2", "substring 2 is 2"); xfree(s); s = xregex_match_sub_strdup(rm, 3); ok (s == NULL, "substring 4 did NOT match"); s = xregex_match_sub_strdup(rm, -1); /* powerman actually does this! */ ok (s == NULL, "substring -1 did NOT match"); s = xregex_match_strdup(rm); is (s, "xxxfoo1bar2", "overall match is xxxfoo1bar2"); ok (xregex_match_strlen(rm) == strlen(s), "xregex_match_strlen returns expected length"); xfree(s); xregex_match_recycle(rm); ok (xregex_exec(re, "foobar2", rm) == false, "regex does NOT match foobar2"); s = xregex_match_sub_strdup(rm, 0); ok (s == NULL, "substring 0 did NOT match"); s = xregex_match_sub_strdup(rm, 1); ok (s == NULL, "substring 1 did NOT match"); xregex_match_recycle(rm); ok (xregex_exec(re, "xxxfoo1bar2yyy", rm) == true, "regex does matches xxxfoo1bar2yyy"); s = xregex_match_sub_strdup(rm, 0); ok (s != NULL, "substring 0 matched"); is (s, "foo1bar2", "substring 0 is foo1bar2"); xfree(s); s = xregex_match_sub_strdup(rm, 1); ok (s != NULL, "substring 1 matched"); is (s, "1", "substring 1 is 1"); xfree(s); s = xregex_match_sub_strdup(rm, 2); ok (s != NULL, "substring 2 matched"); is (s, "2", "substring 2 is 2"); xfree(s); s = xregex_match_strdup(rm); is (s, "xxxfoo1bar2", "overall match is xxxfoo1bar2"); ok (xregex_match_strlen(rm) == strlen(s), "xregex_match_strlen returned expected length"); xfree(s); xregex_match_destroy(rm); xregex_destroy(re); } int main(int argc, char *argv[]) { char *s; plan(NO_PLAN); ok (_match("foo", "foo"), "regex foo matches foo"); ok (_match("foo", "fooxxx"), "regex foo matches fooxxx"); ok (_match("foo", "xxxfoo"), "regex foo matches xxxfoo"); ok (!_match("foo", "bar"), "regex foo does NOT match bar"); _check_substr_match(); /* verify that \\n and \\r are converted into \r and \r */ ok (!_match("foo\\r\\n", "foo\\r\\n"), "regex foo\\\\r\\\\n matches foo\\\\r\\\\n"); ok ( _match("foo\\r\\n", "foo\r\n"), "regex foo\\\\r\\\\n does NOT match foo\\r\\n"); /* check a really long string for a regex */ #define LONG_STR_LEN (64*1024*1024) #define POS_MAGIC 42 #define POS_WONDERFUL 32*1024*1024 #define POS_COOKIE 63*1024*1024 s = xmalloc(LONG_STR_LEN); memset(s, 'a', LONG_STR_LEN - 1); memcpy(s + POS_MAGIC, "MAGIC", 5); memcpy(s + POS_WONDERFUL, "WONDERFUL", 9); memcpy(s + POS_COOKIE, "COOKIE", 6); s[LONG_STR_LEN - 1] = '\0'; ok (_match("MAGIC", s), "regex MAGIC matched %d bytes into a string", POS_MAGIC); ok (_match("WONDERFUL", s), "regex WONDERFUL matched %d bytes into a string", POS_WONDERFUL); ok (_match("COOKIE", s), "regex COOKIE matched %d bytes into a string", POS_COOKIE); ok (!_match("CHOCOLATE", s), "regex CHOCOLATE did NOT match in that long string"); xfree(s); /* end of line handling should be disabled since end of string * (which normally matches) is non-deterministic in powerman. * We should be explicitly matching end-of-line sentinels like * \n in scripts. */ ok (!_match("foo$", "foo"), "regex foo$ did NOT match foo"); ok (!_match("foo$", "foo\n"), "regex foo$ did NOT match foo\\n"); ok (!_match("foo\n", "foo"), "regex foo\\n did NOT match foo"); ok (!_match("foo\n", "bar\nfoo"), "regex foo\\n did NOT match bar\\nfoo"); ok (_match("foo\n", "barfoo\n"), "regex foo\\n matched barfoo\\n"); /* regex takes first match if there are > 1, * but leading wildcard matches greedily */ ok (_matchstr("foo", "abfoocdfoo", "abfoo"), "regex takes first match if there are more than one"); ok (_matchstr_all(".*foo", "abfoocdfoo"), "leading wildcard matches greedily"); /* check that [:space:] character class works inside bracket * expression */ ok (_matchstr_all("bar[0-9[:space:]]*foo", "bar 42 foo"), "[:space:] character class works inside bracket expression"); /* debug apcpdu3 regex */ #define B3RX "([0-9])*[^\r\n]*(ON|OFF)\r\n" ok (_matchstr_all(B3RX, " 2- Outlet 2 ON\r\n"), "apcpdu3 regex test 1 works"); ok (_matchstr_all(B3RX, " 9- ON\r\n"), "apcpdu3 regex test 2 works"); done_testing(); exit(0); } // vi:ts=4 sw=4 expandtab powerman-2.4.4/src/libcommon/xmalloc.c000066400000000000000000000021031467035776500177420ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "xmalloc.h" #include "error.h" char *xmalloc(int size) { char *new; if (!(new = calloc(1, size))) err_exit(false, "out of memory"); return new; } char *xrealloc(char *item , int newsize) { char *new; if (!(new = realloc(item, newsize))) err_exit(false, "out of memory"); return new; } void xfree(void *ptr) { free(ptr); } char *xstrdup(const char *str) { char *cpy; if (!(cpy = strdup(str))) err_exit(false, "out of memory"); return cpy; } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/xmalloc.h000066400000000000000000000012201467035776500177460ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_XMALLOC_H #define PM_XMALLOC_H char *xmalloc(int size); char *xrealloc(char *item, int newsize); void xfree(void *ptr); char *xstrdup(const char *str); int xmemory(void); #endif /* PM_XMALLOC_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/xpoll.c000066400000000000000000000135511467035776500174520ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif /* Force select() on darwin as poll() can't be used on devices (e.g. ptys) * FIXME: This should be a configure-time test. */ #if defined(__APPLE__) && defined(HAVE_POLL) #undef HAVE_POLL #endif #include #include #include #include #include #if HAVE_POLL_H #include #endif #if HAVE_SYS_SELECT_H #include #endif #include #include "xtime.h" #include "xmalloc.h" #include "error.h" #include "xpoll.h" #ifndef MAX #define MAX(x, y) (((x) > (y))? (x) : (y)) #endif #define XPOLLFD_ALLOC_CHUNK 16 struct xpollfd { #if HAVE_POLL unsigned int nfds; unsigned int ufds_size; struct pollfd *ufds; #else /* select */ int maxfd; fd_set rset; fd_set wset; #endif }; #if HAVE_POLL static short xflag2flag(short x) { short f = 0; if ((x & XPOLLIN)) f |= POLLIN; if ((x & XPOLLOUT)) f |= POLLOUT; if ((x & XPOLLHUP)) f |= POLLHUP; if ((x & XPOLLERR)) f |= POLLERR; if ((x & XPOLLNVAL)) f |= POLLNVAL; return f; } static short flag2xflag(short f) { short x = 0; if ((f & POLLIN)) x |= XPOLLIN; if ((f & POLLOUT)) x |= XPOLLOUT; if ((f & POLLHUP)) x |= XPOLLHUP; if ((f & POLLERR)) x |= XPOLLERR; if ((f & POLLNVAL)) x |= XPOLLNVAL; return x; } #endif /* a null tv means no timeout (could block forever) */ int xpoll(xpollfd_t pfd, struct timeval *tv) { struct timeval tv_cpy, *tvp = NULL; struct timeval start, end, delta; int n; if (tv) { tv_cpy = *tv; if (gettimeofday(&start, NULL) < 0) err_exit(true, "gettimeofday"); tvp = &tv_cpy; } /* repeat poll if interrupted */ do { #if HAVE_POLL int tv_msec = -1; if (tvp) tv_msec = tvp->tv_sec * 1000 + tvp->tv_usec / 1000; n = poll(pfd->ufds, pfd->nfds, tv_msec); #else n = select(pfd->maxfd + 1, &pfd->rset, &pfd->wset, NULL, tvp); #endif if (n < 0 && errno != EINTR) err_exit(true, "select/poll"); if (n < 0 && tv != NULL) { if (gettimeofday(&end, NULL) < 0) err_exit(true, "gettimeofday"); timersub(&end, &start, &delta); /* delta = end - start */ timersub(tv, &delta, tvp); /* *tvp = tv - delta */ } } while (n < 0); return n; } #if HAVE_POLL static void _grow_pollfd(xpollfd_t pfd, int n) { while (pfd->ufds_size < n) { pfd->ufds_size += XPOLLFD_ALLOC_CHUNK; pfd->ufds = (struct pollfd *)xrealloc((char *)pfd->ufds, sizeof(struct pollfd) * pfd->ufds_size); } } #endif xpollfd_t xpollfd_create(void) { xpollfd_t pfd = (xpollfd_t)xmalloc(sizeof(struct xpollfd)); #if HAVE_POLL pfd->ufds_size += XPOLLFD_ALLOC_CHUNK; pfd->ufds = (struct pollfd *)xmalloc(sizeof(struct pollfd)*pfd->ufds_size); pfd->nfds = 0; #else pfd->maxfd = 0; FD_ZERO(&pfd->rset); FD_ZERO(&pfd->wset); #endif return pfd; } void xpollfd_destroy(xpollfd_t pfd) { #if HAVE_POLL if (pfd->ufds != NULL) xfree(pfd->ufds); #endif xfree(pfd); } void xpollfd_zero(xpollfd_t pfd) { #if HAVE_POLL pfd->nfds = 0; /*memset(pfd->ufds, 0, sizeof(struct pollfd) * pfd->ufds_size);*/ #else FD_ZERO(&pfd->rset); FD_ZERO(&pfd->wset); pfd->maxfd = 0; #endif } void xpollfd_set(xpollfd_t pfd, int fd, short events) { #if HAVE_POLL int i; for (i = 0; i < pfd->nfds; i++) { if (pfd->ufds[i].fd == fd) { pfd->ufds[i].events |= xflag2flag(events); break; } } if (i == pfd->nfds) { /* not found */ _grow_pollfd(pfd, ++pfd->nfds); pfd->ufds[i].fd = fd; pfd->ufds[i].events = xflag2flag(events); } #else assert(fd < FD_SETSIZE); if (events & XPOLLIN) FD_SET(fd, &pfd->rset); if (events & XPOLLOUT) FD_SET(fd, &pfd->wset); pfd->maxfd = MAX(pfd->maxfd, fd); #endif } char * xpollfd_str(xpollfd_t pfd, char *str, int len) { int i; #if HAVE_POLL int maxfd = -1; #endif #if HAVE_POLL memset(str, '.', len); for (i = 0; i < pfd->nfds; i++) { int fd = pfd->ufds[i].fd; short revents = pfd->ufds[i].revents; if (fd < len - 1) { if (revents) { if (revents & (POLLNVAL | POLLERR | POLLHUP)) str[fd] = 'E'; else if (revents & POLLIN) str[fd] = 'I'; else if (revents & POLLOUT) str[fd] = 'O'; } if (fd > maxfd) maxfd = fd; } } assert(maxfd + 1 < len); str[maxfd + 1] = '\0'; #else for (i = 0; i <= pfd->maxfd; i++) { if (FD_ISSET(i, &pfd->rset)) str[i] = 'I'; else if (FD_ISSET(i, &pfd->wset)) str[i] = 'O'; else str[i] = '.'; } assert(i < len); str[i] = '\0'; #endif return str; } short xpollfd_revents(xpollfd_t pfd, int fd) { short flags = 0; #if HAVE_POLL int i; for (i = 0; i < pfd->nfds; i++) { if (pfd->ufds[i].fd == fd) { flags = flag2xflag(pfd->ufds[i].revents); break; } } #else if (FD_ISSET(fd, &pfd->rset)) flags |= XPOLLIN; if (FD_ISSET(fd, &pfd->wset)) flags |= XPOLLOUT; #endif return flags; } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/xpoll.h000066400000000000000000000017671467035776500174650ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_XPOLL_H #define PM_XPOLL_H typedef struct xpollfd *xpollfd_t; int xpoll(xpollfd_t pfd, struct timeval *timeout); xpollfd_t xpollfd_create(void); void xpollfd_destroy(xpollfd_t pfd); void xpollfd_zero(xpollfd_t pfd); void xpollfd_set(xpollfd_t pfd, int fd, short events); short xpollfd_revents(xpollfd_t pfd, int fd); char *xpollfd_str(xpollfd_t pfd, char *str, int len); #define XPOLLIN 1 #define XPOLLOUT 2 #define XPOLLHUP 4 #define XPOLLERR 8 #define XPOLLNVAL 16 #endif /* PM_XPOLL_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/xread.c000066400000000000000000000052501467035776500174140ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include "xread.h" #include "xmalloc.h" #include "error.h" int xread(int fd, char *p, int max) { int n; do { n = read(fd, p, max); } while (n < 0 && errno == EINTR); if (n < 0 && errno != EWOULDBLOCK && errno != ECONNRESET) err_exit(true, "read"); return n; } #define CHUNKSIZE 80 char *xreadstr(int fd) { int size = 0; int len = 0; char *str = NULL; int n; do { if (size - len - 1 <= 0) { str = (size == 0) ? xmalloc(CHUNKSIZE) : xrealloc(str, size + CHUNKSIZE); size += CHUNKSIZE; } //n = xread(fd, str + len, size - len - 1); n = xread(fd, str + len, 1); if (n < 0) err_exit (true, "read"); if (n == 0) err_exit (false, "EOF on read"); len += n; str[len] = '\0'; } while (len < 2 || strcmp(&str[len - 2], "\r\n") != 0); str[len - 2] = '\0'; return str; } int xwrite(int fd, char *p, int max) { int n; do { n = write(fd, p, max); } while (n < 0 && errno == EINTR); if (n < 0 && errno != EAGAIN && errno != ECONNRESET && errno != EPIPE) err_exit(true, "write"); return n; } void xwrite_all(int fd, char *p, int count) { int n; int done = 0; while (done < count) { n = xwrite(fd, p + done, count - done); if (n < 0) err_exit(true, "write"); done += n; } } void xread_all(int fd, char *p, int count) { int n; int done = 0; while (done < count) { n = xread(fd, p + done, count - done); if (n < 0) err_exit(true, "read"); if (n == 0) err_exit(false, "EOF on read"); done += n; } } static void _zap_trailing_whitespace(char *s) { char *p = s + strlen(s) - 1; while (p >= s && isspace(*p)) *p-- = '\0'; } char *xreadline(char *prompt, char *buf, int buflen) { printf("%s", prompt); fflush(stdout); if (fgets(buf, buflen, stdin) == NULL) return NULL; _zap_trailing_whitespace(buf); return buf; } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/xread.h000066400000000000000000000026061467035776500174230ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_XREAD_H #define PM_XREAD_H /* Read function that handles EINTR internally and terminates on all * other errors except EWOULDBLOCK and ECONNRESET. */ int xread(int fd, char *p, int max); /* Write function that handles EINTR internally and terminates on all * other errors except EPIPE, EWOULDBLOCK, and ECONNRESET. */ int xwrite(int fd, char *p, int max); /* Wrapper for xread that reads exactly count bytes or dies trying */ void xread_all(int fd, char *p, int count); /* Wrapper for xwrite that writes exactly count bytes or dies trying. */ void xwrite_all(int fd, char *p, int count); /* Read a line of input, strip whitespace off the end, and return it. */ char *xreadline(char *prompt, char *buf, int buflen); /* Read a line of data from file descriptor, terminated with \r\n, * which is not returned. Exit on EOF or read error. * Caller must free returned string (null terminated). */ char *xreadstr(int fd); #endif /* PM_XREAD_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/xregex.c000066400000000000000000000114321467035776500176120ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include "error.h" #include "xregex.h" #include "xmalloc.h" struct xregex_struct { int xr_cflags; regex_t *xr_regex; }; struct xregex_match_struct { int xm_nmatch; regmatch_t *xm_pmatch; char *xm_str; int xm_result; bool xm_used; }; xregex_t xregex_create(void) { xregex_t xrp = (xregex_t)xmalloc(sizeof(struct xregex_struct)); xrp->xr_regex = NULL; return xrp; } void xregex_destroy(xregex_t xrp) { if (xrp->xr_regex) { regfree(xrp->xr_regex); xfree(xrp->xr_regex); } xfree(xrp); } /* Substitute all occurrences of s2 with s3 in s1, * e.g. _str_subst(str, "\\r", "\r") */ static void _str_subst(char *s1, int len, const char *s2, const char *s3) { int s2len = strlen(s2); int s3len = strlen(s3); char *p; while ((p = strstr(s1, s2)) != NULL) { assert(strlen(s1) + (s3len - s2len) + 1 <= len); memmove(p + s3len, p + s2len, strlen(p + s2len) + 1); memcpy(p, s3, s3len); } } void xregex_compile(xregex_t xrp, const char *regex, bool withsub) { char tmpstr[256]; char *cpy; int n; assert(regex != NULL); assert(xrp->xr_regex == NULL); /* No particular limit is imposed on the length of REs(!). Programs * intended to be portable should not employ REs longer than 256 bytes, as * an implementation can refuse to accept such REs and remain POSIX-com- * pliant. -- regex(7) on RHEL 5 */ if (strlen(regex) > 256) err_exit(false, "refusing to compile regex > 256 bytes"); xrp->xr_regex = (regex_t *)xmalloc(sizeof(regex_t)); xrp->xr_cflags = REG_EXTENDED; if (!withsub) xrp->xr_cflags |= REG_NOSUB; cpy = xstrdup(regex); _str_subst(cpy, strlen(cpy) + 1, "\\r", "\r"); _str_subst(cpy, strlen(cpy) + 1, "\\n", "\n"); n = regcomp(xrp->xr_regex, cpy, xrp->xr_cflags); xfree(cpy); if (n != 0) { regerror(n, xrp->xr_regex, tmpstr, sizeof(tmpstr)); err_exit(false, "regcomp failed: %s", tmpstr); } } bool xregex_exec(xregex_t xrp, const char *s, xregex_match_t xm) { int eflags = REG_NOTEOL; int res; assert(xrp->xr_regex != NULL); if (xm != NULL) { assert(xm->xm_used == false); } res = regexec(xrp->xr_regex, s, xm ? xm->xm_nmatch : 0, xm ? xm->xm_pmatch : NULL, eflags); if (xm != NULL) { xm->xm_result = res; xm->xm_used = true; if (res == 0) { if (xm->xm_str) xfree(xm->xm_str); xm->xm_str = xstrdup(s); } } return res == 0 ? true : false; } xregex_match_t xregex_match_create(int nmatch) { xregex_match_t xm; xm = (xregex_match_t)xmalloc(sizeof(struct xregex_match_struct)); xm->xm_nmatch = nmatch + 1; xm->xm_pmatch = (regmatch_t *)xmalloc(sizeof(regmatch_t) * (nmatch + 1)); xm->xm_str = NULL; xm->xm_result = -1; xm->xm_used = false; return xm; } void xregex_match_destroy(xregex_match_t xm) { xfree(xm->xm_pmatch); if (xm->xm_str) xfree(xm->xm_str); xfree(xm); } void xregex_match_recycle(xregex_match_t xm) { if (xm->xm_str) { xfree(xm->xm_str); xm->xm_str = NULL; } xm->xm_result = -1; xm->xm_used = false; } char * xregex_match_strdup(xregex_match_t xm) { char *s = NULL; assert(xm->xm_used); if (xm->xm_result == 0) { s = (char *)xmalloc(xm->xm_pmatch[0].rm_eo + 1); assert(xm->xm_str != NULL); memcpy(s, xm->xm_str, xm->xm_pmatch[0].rm_eo); s[xm->xm_pmatch[0].rm_eo] = '\0'; } return s; } int xregex_match_strlen(xregex_match_t xm) { assert(xm->xm_used); return xm->xm_pmatch[0].rm_eo; } char * xregex_match_sub_strdup(xregex_match_t xm, int i) { char *s = NULL; assert(xm->xm_used); if (xm->xm_result == 0 && i >= 0 && i < xm->xm_nmatch && xm->xm_pmatch[i].rm_so != -1) { regmatch_t m = xm->xm_pmatch[i]; assert(xm->xm_str != NULL); assert(m.rm_so < m.rm_eo); s = xmalloc(m.rm_eo - m.rm_so + 1); memcpy(s, xm->xm_str + m.rm_so, m.rm_eo - m.rm_so); s[m.rm_eo - m.rm_so] = '\0'; } return s; } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/xregex.h000066400000000000000000000045041467035776500176210ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_XREGEX_H #define PM_XREGEX_H #include /* A compiled regex. */ typedef struct xregex_struct *xregex_t; /* A container for regexec subexpression match results. */ typedef struct xregex_match_struct *xregex_match_t; /* Create/destroy a regex object. */ xregex_t xregex_create(void); void xregex_destroy(xregex_t x); /* Compile a regex defined by 's' into a regex object created with * xregex_create(). 's' may contain the strings "\n" or "\r" in expanded * form and they will be converted into 0xa and 0xd respectively. * If 'withsub' is true, the regex will support subexpression matches. * Program terminates with detailed message on compilation error. */ void xregex_compile(xregex_t x, const char *s, bool withsub); /* Execute a compiled regex against the provided string 's'. * If xm is non-NULL, place match info there. * Returns true on a match. */ bool xregex_exec(xregex_t x, const char *s, xregex_match_t xm); /* Create/destroy/recycle a match result object. * The maximum number of matches is specified at creation in 'nmatch'. * Allow one match for main expression, and an additional match for * each subexpression. */ xregex_match_t xregex_match_create(int nmatch); void xregex_match_destroy(xregex_match_t xm); void xregex_match_recycle(xregex_match_t xm); /* Retrieve a copy of the main/subexpression match specified by 'index', * or NULL if no match. The caller must free result with xfree(). * Index 0 is for the main expression, other indices are for subexpressions. * This function must be called only after xregex_exec(). */ char *xregex_match_sub_strdup(xregex_match_t xm, int index); /* Similar to xregex_match_sub_strdup(xm, 0) but includes unmatched * leading text. Caller must free result with xfree(). */ char *xregex_match_strdup(xregex_match_t xm); /* Strlen of above. */ int xregex_match_strlen(xregex_match_t xm); #endif /* PM_XREGEX_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/xsignal.c000066400000000000000000000020531467035776500177540ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif #include #include "error.h" #include "xsignal.h" xsigfunc_t *xsignal(int signo, xsigfunc_t *func) { struct sigaction act, oact; int n; act.sa_handler = func; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (signo == SIGALRM) { #ifdef SA_INTERRUPT act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */ #endif } else { #ifdef SA_RESTART act.sa_flags |= SA_RESTART; /* SVR4, 44BSD */ #endif } n = sigaction(signo, &act, &oact); if (n < 0) err_exit(true, "sigaction"); return (oact.sa_handler); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/xsignal.h000066400000000000000000000011251467035776500177600ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_XSIGNAL_H #define PM_XSIGNAL_H typedef void xsigfunc_t(int); xsigfunc_t *xsignal(int signo, xsigfunc_t * func); #endif /* PM_XSIGNAL_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libcommon/xtime.h000066400000000000000000000030701467035776500174420ustar00rootroot00000000000000/* borrowed from glibc-2.5 */ #ifndef PM_XTIME_H #define PM_XTIME_H #ifndef timeradd # define timeradd(a, b, result) \ do { \ (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ if ((result)->tv_usec >= 1000000) \ { \ ++(result)->tv_sec; \ (result)->tv_usec -= 1000000; \ } \ } while (0) #endif #ifndef timersub # define timersub(a, b, result) \ do { \ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ if ((result)->tv_usec < 0) { \ --(result)->tv_sec; \ (result)->tv_usec += 1000000; \ } \ } while (0) #endif #endif /* PM_XTIME_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/libczmq/000077500000000000000000000000001467035776500156255ustar00rootroot00000000000000powerman-2.4.4/src/libczmq/Makefile.am000066400000000000000000000004021467035776500176550ustar00rootroot00000000000000AM_CFLAGS = \ $(WARNING_CFLAGS) noinst_LTLIBRARIES = \ libczmq.la libczmq_la_SOURCES = \ czmq.h \ czmq_internal.h \ czmq_internal.c \ zhashx.h \ zhashx.c \ zhash_primes.inc \ zlistx.h \ zlistx.c \ zhash.h \ zhash.c \ zlist.h \ zlist.c powerman-2.4.4/src/libczmq/czmq.h000066400000000000000000000015421467035776500167520ustar00rootroot00000000000000/************************************************************\ * Copyright 2021 Lawrence Livermore National Security, LLC * (c.f. AUTHORS, NOTICE.LLNS, COPYING) * * This file is part of the Flux resource manager framework. * For details, see https://github.com/flux-framework. * * SPDX-License-Identifier: LGPL-3.0 \************************************************************/ #ifndef _CZMQ_CONTAINERS_H #define _CZMQ_CONTAINERS_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include typedef struct _zhashx_t zhashx_t; typedef struct _zlistx_t zlistx_t; typedef struct _zhash_t zhash_t; typedef struct _zlist_t zlist_t; #ifndef CZMQ_EXPORT #define CZMQ_EXPORT #endif #include "zhashx.h" #include "zlistx.h" #include "zhash.h" #include "zlist.h" #ifdef __cplusplus } #endif #endif powerman-2.4.4/src/libczmq/czmq_internal.c000066400000000000000000000015221467035776500206370ustar00rootroot00000000000000/* ========================================================================= Copyright (c) the Contributors as noted in the AUTHORS file. This file is part of CZMQ, the high-level C binding for 0MQ: http://czmq.zeromq.org. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. ========================================================================= */ #include "czmq.h" #include "czmq_internal.h" // -------------------------------------------------------------------------- // Free a provided string, and nullify the parent pointer. Safe to call on // a null pointer. void zstr_free (char **string_p) { assert (string_p); free (*string_p); *string_p = NULL; } powerman-2.4.4/src/libczmq/czmq_internal.h000066400000000000000000000031141467035776500206430ustar00rootroot00000000000000/* ========================================================================= Copyright (c) the Contributors as noted in the AUTHORS file. This file is part of CZMQ, the high-level C binding for 0MQ: http://czmq.zeromq.org. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. ========================================================================= */ /* To avoid copying in an excess amount of code from czmq, the * following have been manually cut and pasted in */ #ifndef __CZMQ_INTERNAL__ #define __CZMQ_INTERNAL__ #if HAVE_CONFIG_H # include "config.h" #endif #include #include #include #ifdef NDEBUG #undef NDEBUG #include #define NDEBUG #else #include #endif #define freen(x) do {free(x); x = NULL;} while(0) // Replacement for malloc() which asserts if we run out of heap, and // which zeroes the allocated block. static inline void * safe_malloc (size_t size, const char *file, unsigned line) { // printf ("%s:%u %08d\n", file, line, (int) size); void *mem = calloc (1, size); if (mem == NULL) { fprintf (stderr, "FATAL ERROR at %s:%u\n", file, line); fprintf (stderr, "OUT OF MEMORY (malloc returned NULL)\n"); fflush (stderr); abort (); } return mem; } #define zmalloc(size) safe_malloc((size), __FILE__, __LINE__) #define streq(s1,s2) (!strcmp((s1), (s2))) void zstr_free (char **string_p); #endif powerman-2.4.4/src/libczmq/zhash.c000066400000000000000000000724041467035776500171150ustar00rootroot00000000000000/* ========================================================================= zhash - simple generic hash container Copyright (c) the Contributors as noted in the AUTHORS file. This file is part of CZMQ, the high-level C binding for 0MQ: http://czmq.zeromq.org. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. ========================================================================= */ /* @header zhash is an expandable hash table container. This is a simple container. For heavy-duty applications we recommend using zhashx. @discuss Note that it's relatively slow (~50K insertions/deletes per second), so don't do inserts/updates on the critical path for message I/O. It can do ~2.5M lookups per second for 16-char keys. Timed on a 1.6GHz CPU. @end */ #include "czmq.h" #include "czmq_internal.h" // Hash table performance parameters #define INITIAL_SIZE 255 // Initial size in items #define LOAD_FACTOR 75 // Percent loading before splitting #define GROWTH_FACTOR 200 // Increase in % after splitting // Hash item, used internally only typedef struct _item_t { void *value; // Opaque item value struct _item_t *next; // Next item in the hash slot size_t index; // Index of item in table char *key; // Item's original key zhash_free_fn *free_fn; // Value free function if any } item_t; // --------------------------------------------------------------------- // Structure of our class struct _zhash_t { size_t size; // Current size of hash table size_t limit; // Current hash table limit item_t **items; // Array of items size_t cached_index; // Avoids duplicate hash calculations bool autofree; // If true, free values in destructor size_t cursor_index; // For first/next iteration item_t *cursor_item; // For first/next iteration const char *cursor_key; // After first/next call, points to key zlist_t *comments; // File comments, if any time_t modified; // Set during zhash_load char *filename; // Set during zhash_load }; // Local helper functions static uint s_item_hash (const char *key, size_t limit); static item_t *s_item_lookup (zhash_t *self, const char *key); static item_t *s_item_insert (zhash_t *self, const char *key, void *value); static void s_item_destroy (zhash_t *self, item_t *item, bool hard); // -------------------------------------------------------------------------- // Hash table constructor zhash_t * zhash_new (void) { zhash_t *self = (zhash_t *) zmalloc (sizeof (zhash_t)); assert (self); self->limit = INITIAL_SIZE; self->items = (item_t **) zmalloc (sizeof (item_t *) * self->limit); assert (self->items); return self; } // -------------------------------------------------------------------------- // Hash table destructor void zhash_destroy (zhash_t **self_p) { assert (self_p); if (*self_p) { zhash_t *self = *self_p; uint index; for (index = 0; index < self->limit; index++) { // Destroy all items in this hash bucket item_t *cur_item = self->items [index]; while (cur_item) { item_t *next_item = cur_item->next; s_item_destroy (self, cur_item, true); cur_item = next_item; } } if (self->items) freen (self->items); zlist_destroy (&self->comments); freen (self->filename); freen (self); *self_p = NULL; } } // -------------------------------------------------------------------------- // Local helper function // Destroy item in hash table, item must exist in table static void s_item_destroy (zhash_t *self, item_t *item, bool hard) { // Find previous item since it's a singly-linked list item_t *cur_item = self->items [item->index]; item_t **prev_item = &(self->items [item->index]); while (cur_item) { if (cur_item == item) break; prev_item = &(cur_item->next); cur_item = cur_item->next; } assert (cur_item); *prev_item = item->next; self->size--; if (hard) { if (item->free_fn) (item->free_fn) (item->value); else if (self->autofree) freen (item->value); freen (item->key); self->cursor_item = NULL; self->cursor_key = NULL; freen (item); } } // -------------------------------------------------------------------------- // Insert item into hash table with specified key and item // If key is already present returns -1 and leaves existing item unchanged // Returns 0 on success. int zhash_insert (zhash_t *self, const char *key, void *value) { assert (self); assert (key); // If we're exceeding the load factor of the hash table, // resize it according to the growth factor if (self->size >= self->limit * LOAD_FACTOR / 100) { // Create new hash table size_t new_limit = self->limit * GROWTH_FACTOR / 100; item_t **new_items = (item_t **) zmalloc (sizeof (item_t *) * new_limit); if (!new_items) return -1; // Move all items to the new hash table, rehashing to // take into account new hash table limit uint index; for (index = 0; index != self->limit; index++) { item_t *cur_item = self->items [index]; while (cur_item) { item_t *next_item = cur_item->next; uint new_index = s_item_hash (cur_item->key, new_limit); cur_item->index = new_index; cur_item->next = new_items [new_index]; new_items [new_index] = cur_item; cur_item = next_item; } } // Destroy old hash table freen (self->items); self->items = new_items; self->limit = new_limit; } return s_item_insert (self, key, value)? 0: -1; } // -------------------------------------------------------------------------- // Local helper function // Compute hash for key string static uint s_item_hash (const char *key, size_t limit) { // Modified Bernstein hashing function uint key_hash = 0; while (*key) key_hash = 33 * key_hash ^ *key++; key_hash %= limit; return key_hash; } // -------------------------------------------------------------------------- // Local helper function // Insert new item into hash table, returns item // If item already existed, returns NULL static item_t * s_item_insert (zhash_t *self, const char *key, void *value) { // Check that item does not already exist in hash table // Leaves self->cached_index with calculated hash item item_t *item = s_item_lookup (self, key); if (item == NULL) { item = (item_t *) zmalloc (sizeof (item_t)); assert (item); // If necessary, take duplicate of item (string) value if (self->autofree) { value = strdup ((char *) value); assert (value); } item->value = value; item->key = strdup (key); item->index = self->cached_index; // Insert into start of bucket list item->next = self->items [self->cached_index]; self->items [self->cached_index] = item; self->size++; } else item = NULL; // Signal duplicate insertion return item; } // -------------------------------------------------------------------------- // Local helper function // Lookup item in hash table, returns item or NULL static item_t * s_item_lookup (zhash_t *self, const char *key) { // Look in bucket list for item by key self->cached_index = s_item_hash (key, self->limit); item_t *item = self->items [self->cached_index]; while (item) { if (streq (item->key, key)) break; item = item->next; } return item; } // -------------------------------------------------------------------------- // Update item into hash table with specified key and item. // If key is already present, destroys old item and inserts new one. // Use free_fn method to ensure deallocator is properly called on item. void zhash_update (zhash_t *self, const char *key, void *value) { assert (self); assert (key); item_t *item = s_item_lookup (self, key); if (item) { if (item->free_fn) (item->free_fn) (item->value); else if (self->autofree) freen (item->value); // If necessary, take duplicate of item (string) value if (self->autofree) { value = strdup ((char *) value); assert (value); } item->value = value; } else zhash_insert (self, key, value); } // -------------------------------------------------------------------------- // Remove an item specified by key from the hash table. If there was no such // item, this function does nothing. void zhash_delete (zhash_t *self, const char *key) { assert (self); assert (key); item_t *item = s_item_lookup (self, key); if (item) s_item_destroy (self, item, true); } // -------------------------------------------------------------------------- // Look for item in hash table and return its item, or NULL void * zhash_lookup (zhash_t *self, const char *key) { assert (self); assert (key); item_t *item = s_item_lookup (self, key); if (item) return item->value; else return NULL; } // -------------------------------------------------------------------------- // Reindexes an item from an old key to a new key. If there was no such // item, does nothing. If the new key already exists, deletes old item. int zhash_rename (zhash_t *self, const char *old_key, const char *new_key) { item_t *old_item = s_item_lookup (self, old_key); item_t *new_item = s_item_lookup (self, new_key); if (old_item && !new_item) { s_item_destroy (self, old_item, false); freen (old_item->key); old_item->key = strdup (new_key); assert (old_item->key); old_item->index = self->cached_index; old_item->next = self->items [self->cached_index]; self->items [self->cached_index] = old_item; self->size++; return 0; } else return -1; } // -------------------------------------------------------------------------- // Set a free function for the specified hash table item. When the item is // destroyed, the free function, if any, is called on that item. // Use this when hash items are dynamically allocated, to ensure that // you don't have memory leaks. You can pass 'free' or NULL as a free_fn. // Returns the item, or NULL if there is no such item. void * zhash_freefn (zhash_t *self, const char *key, zhash_free_fn free_fn) { assert (self); assert (key); item_t *item = s_item_lookup (self, key); if (item) { item->free_fn = free_fn; return item->value; } else return NULL; } // -------------------------------------------------------------------------- // Return size of hash table size_t zhash_size (zhash_t *self) { assert (self); return self->size; } // -------------------------------------------------------------------------- // Make copy of hash table // Does not copy items themselves. Rebuilds new table so may be slow on // very large tables. NOTE: only works with item values that are strings // since there's no other way to know how to duplicate the item value. zhash_t * zhash_dup (zhash_t *self) { if (!self) return NULL; zhash_t *copy = zhash_new (); zhash_autofree (copy); if (copy) { uint index; for (index = 0; index != self->limit; index++) { item_t *item = self->items [index]; while (item) { zhash_insert (copy, item->key, item->value); item = item->next; } } } return copy; } // -------------------------------------------------------------------------- // Return keys for items in table zlist_t * zhash_keys (zhash_t *self) { assert (self); zlist_t *keys = zlist_new (); if (!keys) return NULL; zlist_autofree (keys); uint index; for (index = 0; index != self->limit; index++) { item_t *item = self->items [index]; while (item) { zlist_append (keys, item->key); item = item->next; } } return keys; } // -------------------------------------------------------------------------- // Simple iterator; returns first item in hash table, in no given order, // or NULL if the table is empty. This method is simpler to use than the // foreach() method, which is deprecated. NOTE: do NOT modify the table // while iterating. void * zhash_first (zhash_t *self) { assert (self); // Point to before or at first item self->cursor_index = 0; self->cursor_item = self->items [self->cursor_index]; // Now scan forwards to find it, leave cursor after item return zhash_next (self); } // -------------------------------------------------------------------------- // Simple iterator; returns next item in hash table, in no given order, // or NULL if the last item was already returned. Use this together with // zhash_first() to process all items in a hash table. If you need the // items in sorted order, use zhash_keys() and then zlist_sort(). NOTE: // do NOT modify the table while iterating. void * zhash_next (zhash_t *self) { assert (self); // Scan forward from cursor until we find an item while (self->cursor_item == NULL) { if (self->cursor_index < self->limit - 1) self->cursor_index++; else return NULL; // At end of table // Get first item in next bucket self->cursor_item = self->items [self->cursor_index]; } // We have an item, so return it, and bump past it assert (self->cursor_item); item_t *item = self->cursor_item; self->cursor_key = item->key; self->cursor_item = self->cursor_item->next; return item->value; } // -------------------------------------------------------------------------- // After a successful first/next method, returns the key for the item that // was returned. This is a constant string that you may not modify or // deallocate, and which lasts as long as the item in the hash. After an // unsuccessful first/next, returns NULL. const char * zhash_cursor (zhash_t *self) { assert (self); return self->cursor_key; } #ifdef CZMQ_BUILD_EXTRA // -------------------------------------------------------------------------- // Add a comment to hash table before saving to disk. You can add as many // comment lines as you like. These comment lines are discarded when loading // the file. If you use a null format, all comments are deleted. void zhash_comment (zhash_t *self, const char *format, ...) { if (format) { if (!self->comments) { self->comments = zlist_new (); if (!self->comments) return; zlist_autofree (self->comments); } va_list argptr; va_start (argptr, format); char *string = zsys_vprintf (format, argptr); va_end (argptr); if (string) zlist_append (self->comments, string); zstr_free (&string); } else zlist_destroy (&self->comments); } // -------------------------------------------------------------------------- // Save hash table to a text file in name=value format // Hash values must be printable strings. // Returns 0 if OK, else -1 if a file error occurred int zhash_save (zhash_t *self, const char *filename) { assert (self); FILE *handle = fopen (filename, "w"); if (!handle) return -1; // Failed to create file if (self->comments) { char *comment = (char *) zlist_first (self->comments); while (comment) { fprintf (handle, "# %s\n", comment); comment = (char *) zlist_next (self->comments); } fprintf (handle, "\n"); } uint index; for (index = 0; index != self->limit; index++) { item_t *item = self->items [index]; while (item) { fprintf (handle, "%s=%s\n", item->key, (char *) item->value); item = item->next; } } fclose (handle); return 0; } // -------------------------------------------------------------------------- // Load hash table from a text file in name=value format; hash table must // already exist. Hash values must printable strings. // Returns 0 if OK, else -1 if a file was not readable. int zhash_load (zhash_t *self, const char *filename) { assert (self); zhash_autofree (self); // Whether or not file exists, we'll track the filename and last // modification date (0 for unknown files), so that zhash_refresh () // will always work after zhash_load (), to load a newly-created // file. // Take copy of filename in case self->filename is same string. char *filename_copy = strdup (filename); assert (filename_copy); freen (self->filename); self->filename = filename_copy; self->modified = zsys_file_modified (self->filename); FILE *handle = fopen (self->filename, "r"); if (handle) { char *buffer = (char *) zmalloc (1024); assert (buffer); while (fgets (buffer, 1024, handle)) { // Skip lines starting with "#" or that do not look like // name=value data. char *equals = strchr (buffer, '='); if (buffer [0] == '#' || equals == buffer || !equals) continue; // Buffer may end in newline, which we don't want if (buffer [strlen (buffer) - 1] == '\n') buffer [strlen (buffer) - 1] = 0; *equals++ = 0; zhash_update (self, buffer, equals); } freen (buffer); fclose (handle); } else return -1; // Failed to open file for reading return 0; } // -------------------------------------------------------------------------- // When a hash table was loaded from a file by zhash_load, this method will // reload the file if it has been modified since, and is "stable", i.e. not // still changing. Returns 0 if OK, -1 if there was an error reloading the // file. int zhash_refresh (zhash_t *self) { assert (self); if (self->filename) { if (zsys_file_modified (self->filename) > self->modified && zsys_file_stable (self->filename)) { // Empty the hash table; code is copied from zhash_destroy uint index; for (index = 0; index < self->limit; index++) { // Destroy all items in this hash bucket item_t *cur_item = self->items [index]; while (cur_item) { item_t *next_item = cur_item->next; s_item_destroy (self, cur_item, true); cur_item = next_item; } } zhash_load (self, self->filename); } } return 0; } // -------------------------------------------------------------------------- // Serialize hash table to a binary frame that can be sent in a message. // The packed format is compatible with the 'dictionary' type defined in // http://rfc.zeromq.org/spec:35/FILEMQ, and implemented by zproto: // // ; A list of name/value pairs // dictionary = dict-count *( dict-name dict-value ) // dict-count = number-4 // dict-value = longstr // dict-name = string // // ; Strings are always length + text contents // longstr = number-4 *VCHAR // string = number-1 *VCHAR // // ; Numbers are unsigned integers in network byte order // number-1 = 1OCTET // number-4 = 4OCTET // // Comments are not included in the packed data. Item values MUST be // strings. zframe_t * zhash_pack (zhash_t *self) { assert (self); // First, calculate packed data size size_t frame_size = 4; // Dictionary size, number-4 uint index; for (index = 0; index < self->limit; index++) { item_t *item = self->items [index]; while (item) { // We store key as short string frame_size += 1 + strlen ((char *) item->key); // We store value as long string frame_size += 4 + strlen ((char *) item->value); item = item->next; } } // Now serialize items into the frame zframe_t *frame = zframe_new (NULL, frame_size); if (!frame) return NULL; byte *needle = zframe_data (frame); // Store size as number-4 *(uint32_t *) needle = htonl ((uint32_t) self->size); needle += 4; for (index = 0; index < self->limit; index++) { item_t *item = self->items [index]; while (item) { // Store key as string size_t length = strlen ((char *) item->key); *needle++ = (byte) length; memcpy (needle, item->key, length); needle += length; // Store value as longstr length = strlen ((char *) item->value); uint32_t serialize = htonl ((uint32_t) length); memcpy (needle, &serialize, 4); needle += 4; memcpy (needle, (char *) item->value, length); needle += length; item = item->next; } } return frame; } // -------------------------------------------------------------------------- // Unpack binary frame into a new hash table. Packed data must follow format // defined by zhash_pack. Hash table is set to autofree. An empty frame // unpacks to an empty hash table. zhash_t * zhash_unpack (zframe_t *frame) { zhash_t *self = zhash_new (); if (!self) return NULL; assert (frame); if (zframe_size (frame) < 4) return self; // Arguable... byte *needle = zframe_data (frame); byte *ceiling = needle + zframe_size (frame); size_t nbr_items = ntohl (*(uint32_t *) needle); needle += 4; while (nbr_items && needle < ceiling) { // Get key as string size_t key_size = *needle++; if (needle + key_size <= ceiling) { char key [256]; memcpy (key, needle, key_size); key [key_size] = 0; needle += key_size; // Get value as longstr if (needle + 4 <= ceiling) { size_t value_size = ntohl (*(uint32_t *) needle); needle += 4; // Be wary of malformed frames if (needle + value_size <= ceiling) { char *value = (char *) malloc (value_size + 1); memcpy (value, needle, value_size); value [value_size] = 0; needle += value_size; // Hash takes ownership of value if (zhash_insert (self, key, value)) { zhash_destroy (&self); break; } } } } } // Hash will free values in destructor if (self) zhash_autofree (self); return self; } #endif // CZMQ_BUILD_EXTRA // -------------------------------------------------------------------------- // Set hash for automatic value destruction void zhash_autofree (zhash_t *self) { assert (self); self->autofree = true; } #ifdef CZMQ_BUILD_EXTRA // -------------------------------------------------------------------------- // Runs selftest of class // void zhash_test (bool verbose) { printf (" * zhash: "); // @selftest zhash_t *hash = zhash_new (); assert (hash); assert (zhash_size (hash) == 0); assert (zhash_first (hash) == NULL); assert (zhash_cursor (hash) == NULL); // Insert some items int rc; rc = zhash_insert (hash, "DEADBEEF", "dead beef"); char *item = (char *) zhash_first (hash); assert (streq (zhash_cursor (hash), "DEADBEEF")); assert (streq (item, "dead beef")); assert (rc == 0); rc = zhash_insert (hash, "ABADCAFE", "a bad cafe"); assert (rc == 0); rc = zhash_insert (hash, "C0DEDBAD", "coded bad"); assert (rc == 0); rc = zhash_insert (hash, "DEADF00D", "dead food"); assert (rc == 0); assert (zhash_size (hash) == 4); // Look for existing items item = (char *) zhash_lookup (hash, "DEADBEEF"); assert (streq (item, "dead beef")); item = (char *) zhash_lookup (hash, "ABADCAFE"); assert (streq (item, "a bad cafe")); item = (char *) zhash_lookup (hash, "C0DEDBAD"); assert (streq (item, "coded bad")); item = (char *) zhash_lookup (hash, "DEADF00D"); assert (streq (item, "dead food")); // Look for non-existent items item = (char *) zhash_lookup (hash, "foo"); assert (item == NULL); // Try to insert duplicate items rc = zhash_insert (hash, "DEADBEEF", "foo"); assert (rc == -1); item = (char *) zhash_lookup (hash, "DEADBEEF"); assert (streq (item, "dead beef")); // Some rename tests // Valid rename, key is now LIVEBEEF rc = zhash_rename (hash, "DEADBEEF", "LIVEBEEF"); assert (rc == 0); item = (char *) zhash_lookup (hash, "LIVEBEEF"); assert (streq (item, "dead beef")); // Trying to rename an unknown item to a non-existent key rc = zhash_rename (hash, "WHATBEEF", "NONESUCH"); assert (rc == -1); // Trying to rename an unknown item to an existing key rc = zhash_rename (hash, "WHATBEEF", "LIVEBEEF"); assert (rc == -1); item = (char *) zhash_lookup (hash, "LIVEBEEF"); assert (streq (item, "dead beef")); // Trying to rename an existing item to another existing item rc = zhash_rename (hash, "LIVEBEEF", "ABADCAFE"); assert (rc == -1); item = (char *) zhash_lookup (hash, "LIVEBEEF"); assert (streq (item, "dead beef")); item = (char *) zhash_lookup (hash, "ABADCAFE"); assert (streq (item, "a bad cafe")); // Test keys method zlist_t *keys = zhash_keys (hash); assert (zlist_size (keys) == 4); zlist_destroy (&keys); // Test dup method zhash_t *copy = zhash_dup (hash); assert (zhash_size (copy) == 4); item = (char *) zhash_lookup (copy, "LIVEBEEF"); assert (item); assert (streq (item, "dead beef")); zhash_destroy (©); // Test pack/unpack methods zframe_t *frame = zhash_pack (hash); copy = zhash_unpack (frame); zframe_destroy (&frame); assert (zhash_size (copy) == 4); item = (char *) zhash_lookup (copy, "LIVEBEEF"); assert (item); assert (streq (item, "dead beef")); zhash_destroy (©); // Test save and load zhash_comment (hash, "This is a test file"); zhash_comment (hash, "Created by %s", "czmq_selftest"); zhash_save (hash, ".cache"); copy = zhash_new (); assert (copy); zhash_load (copy, ".cache"); item = (char *) zhash_lookup (copy, "LIVEBEEF"); assert (item); assert (streq (item, "dead beef")); zhash_destroy (©); zsys_file_delete (".cache"); // Delete a item zhash_delete (hash, "LIVEBEEF"); item = (char *) zhash_lookup (hash, "LIVEBEEF"); assert (item == NULL); assert (zhash_size (hash) == 3); // Check that the queue is robust against random usage struct { char name [100]; bool exists; } testset [200]; memset (testset, 0, sizeof (testset)); int testmax = 200, testnbr, iteration; srandom ((unsigned) time (NULL)); for (iteration = 0; iteration < 25000; iteration++) { testnbr = randof (testmax); assert (testnbr != testmax); assert (testnbr < testmax); if (testset [testnbr].exists) { item = (char *) zhash_lookup (hash, testset [testnbr].name); assert (item); zhash_delete (hash, testset [testnbr].name); testset [testnbr].exists = false; } else { sprintf (testset [testnbr].name, "%x-%x", rand (), rand ()); if (zhash_insert (hash, testset [testnbr].name, "") == 0) testset [testnbr].exists = true; } } // Test 10K lookups for (iteration = 0; iteration < 10000; iteration++) item = (char *) zhash_lookup (hash, "DEADBEEFABADCAFE"); // Destructor should be safe to call twice zhash_destroy (&hash); zhash_destroy (&hash); assert (hash == NULL); // Test autofree; automatically copies and frees string values hash = zhash_new (); assert (hash); zhash_autofree (hash); char value [255]; strcpy (value, "This is a string"); rc = zhash_insert (hash, "key1", value); assert (rc == 0); strcpy (value, "Inserting with the same key will fail"); rc = zhash_insert (hash, "key1", value); assert (rc == -1); strcpy (value, "Ring a ding ding"); rc = zhash_insert (hash, "key2", value); assert (rc == 0); assert (streq ((char *) zhash_lookup (hash, "key1"), "This is a string")); assert (streq ((char *) zhash_lookup (hash, "key2"), "Ring a ding ding")); zhash_destroy (&hash); #if defined (__WINDOWS__) zsys_shutdown(); #endif // @end printf ("OK\n"); } #endif // CZMQ_BUILD_EXTRA powerman-2.4.4/src/libczmq/zhash.h000066400000000000000000000161561467035776500171240ustar00rootroot00000000000000/* ========================================================================= zhash - generic type-free hash container (simple) Copyright (c) the Contributors as noted in the AUTHORS file. This file is part of CZMQ, the high-level C binding for 0MQ: http://czmq.zeromq.org. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. ========================================================================= */ #ifndef __FLUXZHASH_H_INCLUDED__ #define __FLUXZHASH_H_INCLUDED__ #ifdef __cplusplus extern "C" { #endif // @warning THE FOLLOWING @INTERFACE BLOCK IS AUTO-GENERATED BY ZPROJECT // @warning Please edit the model at "api/zhash.api" to make changes. // @interface // This is a stable class, and may not change except for emergencies. It // is provided in stable builds. // Callback function for zhash_freefn method typedef void (zhash_free_fn) ( void *data); // Create a new, empty hash container CZMQ_EXPORT zhash_t * zhash_new (void); #ifdef CZMQ_BUILD_EXTRA // Unpack binary frame into a new hash table. Packed data must follow format // defined by zhash_pack. Hash table is set to autofree. An empty frame // unpacks to an empty hash table. CZMQ_EXPORT zhash_t * zhash_unpack (zframe_t *frame); #endif // CZMQ_BUILD_EXTRA // Destroy a hash container and all items in it CZMQ_EXPORT void zhash_destroy (zhash_t **self_p); // Insert item into hash table with specified key and item. // If key is already present returns -1 and leaves existing item unchanged // Returns 0 on success. CZMQ_EXPORT int zhash_insert (zhash_t *self, const char *key, void *item); // Update item into hash table with specified key and item. // If key is already present, destroys old item and inserts new one. // Use free_fn method to ensure deallocator is properly called on item. CZMQ_EXPORT void zhash_update (zhash_t *self, const char *key, void *item); // Remove an item specified by key from the hash table. If there was no such // item, this function does nothing. CZMQ_EXPORT void zhash_delete (zhash_t *self, const char *key); // Return the item at the specified key, or null CZMQ_EXPORT void * zhash_lookup (zhash_t *self, const char *key); // Reindexes an item from an old key to a new key. If there was no such // item, does nothing. Returns 0 if successful, else -1. CZMQ_EXPORT int zhash_rename (zhash_t *self, const char *old_key, const char *new_key); // Set a free function for the specified hash table item. When the item is // destroyed, the free function, if any, is called on that item. // Use this when hash items are dynamically allocated, to ensure that // you don't have memory leaks. You can pass 'free' or NULL as a free_fn. // Returns the item, or NULL if there is no such item. CZMQ_EXPORT void * zhash_freefn (zhash_t *self, const char *key, zhash_free_fn free_fn); // Return the number of keys/items in the hash table CZMQ_EXPORT size_t zhash_size (zhash_t *self); // Make copy of hash table; if supplied table is null, returns null. // Does not copy items themselves. Rebuilds new table so may be slow on // very large tables. NOTE: only works with item values that are strings // since there's no other way to know how to duplicate the item value. // Caller owns return value and must destroy it when done. CZMQ_EXPORT zhash_t * zhash_dup (zhash_t *self); // Return keys for items in table // Caller owns return value and must destroy it when done. CZMQ_EXPORT zlist_t * zhash_keys (zhash_t *self); // Simple iterator; returns first item in hash table, in no given order, // or NULL if the table is empty. This method is simpler to use than the // foreach() method, which is deprecated. To access the key for this item // use zhash_cursor(). NOTE: do NOT modify the table while iterating. CZMQ_EXPORT void * zhash_first (zhash_t *self); // Simple iterator; returns next item in hash table, in no given order, // or NULL if the last item was already returned. Use this together with // zhash_first() to process all items in a hash table. If you need the // items in sorted order, use zhash_keys() and then zlist_sort(). To // access the key for this item use zhash_cursor(). NOTE: do NOT modify // the table while iterating. CZMQ_EXPORT void * zhash_next (zhash_t *self); // After a successful first/next method, returns the key for the item that // was returned. This is a constant string that you may not modify or // deallocate, and which lasts as long as the item in the hash. After an // unsuccessful first/next, returns NULL. CZMQ_EXPORT const char * zhash_cursor (zhash_t *self); #ifdef CZMQ_BUILD_EXTRA // Add a comment to hash table before saving to disk. You can add as many // comment lines as you like. These comment lines are discarded when loading // the file. If you use a null format, all comments are deleted. CZMQ_EXPORT void zhash_comment (zhash_t *self, const char *format, ...) CHECK_PRINTF (2); // Serialize hash table to a binary frame that can be sent in a message. // The packed format is compatible with the 'dictionary' type defined in // http://rfc.zeromq.org/spec:35/FILEMQ, and implemented by zproto: // // ; A list of name/value pairs // dictionary = dict-count *( dict-name dict-value ) // dict-count = number-4 // dict-value = longstr // dict-name = string // // ; Strings are always length + text contents // longstr = number-4 *VCHAR // string = number-1 *VCHAR // // ; Numbers are unsigned integers in network byte order // number-1 = 1OCTET // number-4 = 4OCTET // // Comments are not included in the packed data. Item values MUST be // strings. // Caller owns return value and must destroy it when done. CZMQ_EXPORT zframe_t * zhash_pack (zhash_t *self); // Save hash table to a text file in name=value format. Hash values must be // printable strings; keys may not contain '=' character. Returns 0 if OK, // else -1 if a file error occurred. CZMQ_EXPORT int zhash_save (zhash_t *self, const char *filename); // Load hash table from a text file in name=value format; hash table must // already exist. Hash values must printable strings; keys may not contain // '=' character. Returns 0 if OK, else -1 if a file was not readable. CZMQ_EXPORT int zhash_load (zhash_t *self, const char *filename); // When a hash table was loaded from a file by zhash_load, this method will // reload the file if it has been modified since, and is "stable", i.e. not // still changing. Returns 0 if OK, -1 if there was an error reloading the // file. CZMQ_EXPORT int zhash_refresh (zhash_t *self); #endif // CZMQ_BUILD_EXTRA // Set hash for automatic value destruction. Note that this assumes that // values are NULL-terminated strings. Do not use with different types. CZMQ_EXPORT void zhash_autofree (zhash_t *self); #ifdef CZMQ_BUILD_EXTRA // Self test of this class. CZMQ_EXPORT void zhash_test (bool verbose); #endif // CZMQ_BUILD_EXTRA // @end #ifdef __cplusplus } #endif #endif powerman-2.4.4/src/libczmq/zhash_primes.inc000066400000000000000000000250641467035776500210230ustar00rootroot00000000000000/* ========================================================================= zhash_primes.h - 5 largest primes less than 2^n for n = 4...63 Copyright (c) the Contributors as noted in the AUTHORS file. This file is part of CZMQ, the high-level C binding for 0MQ: http://czmq.zeromq.org. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. ========================================================================= */ /* This is a copy of the czmq zhashx library. * * Due to czmq issue #2173 * (https://github.com/zeromq/czmq/issues/2173) a localized copy was * made instead of waiting for OS distros to pick up the bug fix. * * This file is a verbatim copy with only minor adjustments to header * guards. */ #ifndef __FLUXZHASH_PRIMES_H_INCLUDED__ #define __FLUXZHASH_PRIMES_H_INCLUDED__ #ifdef _MSC_VER # define PORTABLE_LLU(number) number##ULL #else # define PORTABLE_LLU(number) number##LLU #endif static size_t primes [] = { PORTABLE_LLU(3), PORTABLE_LLU(5), PORTABLE_LLU(7), PORTABLE_LLU(11), PORTABLE_LLU(13), // 2^4 PORTABLE_LLU(17), PORTABLE_LLU(19), PORTABLE_LLU(23), PORTABLE_LLU(29), PORTABLE_LLU(31), // 2^5 PORTABLE_LLU(43), PORTABLE_LLU(47), PORTABLE_LLU(53), PORTABLE_LLU(59), PORTABLE_LLU(61), // 2^6 PORTABLE_LLU(103), PORTABLE_LLU(107), PORTABLE_LLU(109), PORTABLE_LLU(113), PORTABLE_LLU(127), // 2^7 PORTABLE_LLU(229), PORTABLE_LLU(233), PORTABLE_LLU(239), PORTABLE_LLU(241), PORTABLE_LLU(251), // 2^8 PORTABLE_LLU(487), PORTABLE_LLU(491), PORTABLE_LLU(499), PORTABLE_LLU(503), PORTABLE_LLU(509), // 2^9 PORTABLE_LLU(997), PORTABLE_LLU(1009), PORTABLE_LLU(1013), PORTABLE_LLU(1019), PORTABLE_LLU(1021), // 2^10 PORTABLE_LLU(2011), PORTABLE_LLU(2017), PORTABLE_LLU(2027), PORTABLE_LLU(2029), PORTABLE_LLU(2039), // 2^11 PORTABLE_LLU(4057), PORTABLE_LLU(4073), PORTABLE_LLU(4079), PORTABLE_LLU(4091), PORTABLE_LLU(4093), // 2^12 PORTABLE_LLU(8161), PORTABLE_LLU(8167), PORTABLE_LLU(8171), PORTABLE_LLU(8179), PORTABLE_LLU(8191), // 2^13 PORTABLE_LLU(16349), PORTABLE_LLU(16361), PORTABLE_LLU(16363), PORTABLE_LLU(16369), PORTABLE_LLU(16381), // 2^14 PORTABLE_LLU(32707), PORTABLE_LLU(32713), PORTABLE_LLU(32717), PORTABLE_LLU(32719), PORTABLE_LLU(32749), // 2^15 PORTABLE_LLU(65449), PORTABLE_LLU(65479), PORTABLE_LLU(65497), PORTABLE_LLU(65519), PORTABLE_LLU(65521), // 2^16 PORTABLE_LLU(131023), PORTABLE_LLU(131041), PORTABLE_LLU(131059), PORTABLE_LLU(131063), PORTABLE_LLU(131071), // 2^17 PORTABLE_LLU(262111), PORTABLE_LLU(262121), PORTABLE_LLU(262127), PORTABLE_LLU(262133), PORTABLE_LLU(262139), // 2^18 PORTABLE_LLU(524243), PORTABLE_LLU(524257), PORTABLE_LLU(524261), PORTABLE_LLU(524269), PORTABLE_LLU(524287), // 2^19 PORTABLE_LLU(1048517), PORTABLE_LLU(1048549), PORTABLE_LLU(1048559), PORTABLE_LLU(1048571), PORTABLE_LLU(1048573), // 2^20 PORTABLE_LLU(2097091), PORTABLE_LLU(2097097), PORTABLE_LLU(2097131), PORTABLE_LLU(2097133), PORTABLE_LLU(2097143), // 2^21 PORTABLE_LLU(4194247), PORTABLE_LLU(4194271), PORTABLE_LLU(4194277), PORTABLE_LLU(4194287), PORTABLE_LLU(4194301), // 2^22 PORTABLE_LLU(8388547), PORTABLE_LLU(8388571), PORTABLE_LLU(8388581), PORTABLE_LLU(8388587), PORTABLE_LLU(8388593), // 2^23 PORTABLE_LLU(16777141), PORTABLE_LLU(16777153), PORTABLE_LLU(16777183), PORTABLE_LLU(16777199), PORTABLE_LLU(16777213), // 2^24 PORTABLE_LLU(33554341), PORTABLE_LLU(33554347), PORTABLE_LLU(33554371), PORTABLE_LLU(33554383), PORTABLE_LLU(33554393), // 2^25 PORTABLE_LLU(67108763), PORTABLE_LLU(67108777), PORTABLE_LLU(67108819), PORTABLE_LLU(67108837), PORTABLE_LLU(67108859), // 2^26 PORTABLE_LLU(134217593), PORTABLE_LLU(134217613), PORTABLE_LLU(134217617), PORTABLE_LLU(134217649), PORTABLE_LLU(134217689), // 2^27 PORTABLE_LLU(268435331), PORTABLE_LLU(268435337), PORTABLE_LLU(268435361), PORTABLE_LLU(268435367), PORTABLE_LLU(268435399), // 2^28 PORTABLE_LLU(536870839), PORTABLE_LLU(536870849), PORTABLE_LLU(536870869), PORTABLE_LLU(536870879), PORTABLE_LLU(536870909), // 2^29 PORTABLE_LLU(1073741719), PORTABLE_LLU(1073741723), PORTABLE_LLU(1073741741), PORTABLE_LLU(1073741783), PORTABLE_LLU(1073741789), // 2^30 PORTABLE_LLU(2147483563), PORTABLE_LLU(2147483579), PORTABLE_LLU(2147483587), PORTABLE_LLU(2147483629), PORTABLE_LLU(2147483647), // 2^31 PORTABLE_LLU(4294967197), PORTABLE_LLU(4294967231), PORTABLE_LLU(4294967279), PORTABLE_LLU(4294967291), PORTABLE_LLU(4294967295), // 2^32 #if __WORDSIZE == 64 PORTABLE_LLU(8589934581), PORTABLE_LLU(8589934585), PORTABLE_LLU(8589934587), PORTABLE_LLU(8589934589), PORTABLE_LLU(8589934591), // 2^33 PORTABLE_LLU(17179869175), PORTABLE_LLU(17179869177), PORTABLE_LLU(17179869179), PORTABLE_LLU(17179869181), PORTABLE_LLU(17179869183), // 2^34 PORTABLE_LLU(34359738359), PORTABLE_LLU(34359738361), PORTABLE_LLU(34359738363), PORTABLE_LLU(34359738365), PORTABLE_LLU(34359738367), // 2^35 PORTABLE_LLU(68719476725), PORTABLE_LLU(68719476727), PORTABLE_LLU(68719476729), PORTABLE_LLU(68719476733), PORTABLE_LLU(68719476735), // 2^36 PORTABLE_LLU(137438953463), PORTABLE_LLU(137438953465), PORTABLE_LLU(137438953467), PORTABLE_LLU(137438953469), PORTABLE_LLU(137438953471), // 2^37 PORTABLE_LLU(274877906935), PORTABLE_LLU(274877906937), PORTABLE_LLU(274877906939), PORTABLE_LLU(274877906941), PORTABLE_LLU(274877906943), // 2^38 PORTABLE_LLU(549755813877), PORTABLE_LLU(549755813879), PORTABLE_LLU(549755813883), PORTABLE_LLU(549755813885), PORTABLE_LLU(549755813887), // 2^39 PORTABLE_LLU(1099511627767), PORTABLE_LLU(1099511627769), PORTABLE_LLU(1099511627771), PORTABLE_LLU(1099511627773), PORTABLE_LLU(1099511627775), // 2^40 PORTABLE_LLU(2199023255543), PORTABLE_LLU(2199023255545), PORTABLE_LLU(2199023255547), PORTABLE_LLU(2199023255549), PORTABLE_LLU(2199023255551), // 2^41 PORTABLE_LLU(4398046511095), PORTABLE_LLU(4398046511097), PORTABLE_LLU(4398046511099), PORTABLE_LLU(4398046511101), PORTABLE_LLU(4398046511103), // 2^42 PORTABLE_LLU(8796093022199), PORTABLE_LLU(8796093022201), PORTABLE_LLU(8796093022203), PORTABLE_LLU(8796093022205), PORTABLE_LLU(8796093022207), // 2^43 PORTABLE_LLU(17592186044407), PORTABLE_LLU(17592186044409), PORTABLE_LLU(17592186044411), PORTABLE_LLU(17592186044413), PORTABLE_LLU(17592186044415), // 2^44 PORTABLE_LLU(35184372088823), PORTABLE_LLU(35184372088825), PORTABLE_LLU(35184372088827), PORTABLE_LLU(35184372088829), PORTABLE_LLU(35184372088831), // 2^45 PORTABLE_LLU(70368744177655), PORTABLE_LLU(70368744177657), PORTABLE_LLU(70368744177659), PORTABLE_LLU(70368744177661), PORTABLE_LLU(70368744177663), // 2^46 PORTABLE_LLU(140737488355319), PORTABLE_LLU(140737488355321), PORTABLE_LLU(140737488355323), PORTABLE_LLU(140737488355325), PORTABLE_LLU(140737488355327), // 2^47 PORTABLE_LLU(281474976710647), PORTABLE_LLU(281474976710649), PORTABLE_LLU(281474976710651), PORTABLE_LLU(281474976710653), PORTABLE_LLU(281474976710655), // 2^48 PORTABLE_LLU(562949953421303), PORTABLE_LLU(562949953421305), PORTABLE_LLU(562949953421307), PORTABLE_LLU(562949953421309), PORTABLE_LLU(562949953421311), // 2^49 PORTABLE_LLU(1125899906842615), PORTABLE_LLU(1125899906842617), PORTABLE_LLU(1125899906842619), PORTABLE_LLU(1125899906842621), PORTABLE_LLU(1125899906842623), // 2^50 PORTABLE_LLU(2251799813685239), PORTABLE_LLU(2251799813685241), PORTABLE_LLU(2251799813685243), PORTABLE_LLU(2251799813685245), PORTABLE_LLU(2251799813685247), // 2^51 PORTABLE_LLU(4503599627370487), PORTABLE_LLU(4503599627370489), PORTABLE_LLU(4503599627370491), PORTABLE_LLU(4503599627370493), PORTABLE_LLU(4503599627370495), // 2^52 PORTABLE_LLU(9007199254740983), PORTABLE_LLU(9007199254740985), PORTABLE_LLU(9007199254740987), PORTABLE_LLU(9007199254740989), PORTABLE_LLU(9007199254740991), // 2^53 PORTABLE_LLU(18014398509481975), PORTABLE_LLU(18014398509481977), PORTABLE_LLU(18014398509481979), PORTABLE_LLU(18014398509481981), PORTABLE_LLU(18014398509481983), // 2^54 PORTABLE_LLU(36028797018963959), PORTABLE_LLU(36028797018963961), PORTABLE_LLU(36028797018963963), PORTABLE_LLU(36028797018963965), PORTABLE_LLU(36028797018963967), // 2^55 PORTABLE_LLU(72057594037927925), PORTABLE_LLU(72057594037927927), PORTABLE_LLU(72057594037927929), PORTABLE_LLU(72057594037927933), PORTABLE_LLU(72057594037927935), // 2^56 PORTABLE_LLU(144115188075855863), PORTABLE_LLU(144115188075855865), PORTABLE_LLU(144115188075855867), PORTABLE_LLU(144115188075855869), PORTABLE_LLU(144115188075855871), // 2^57 PORTABLE_LLU(288230376151711735), PORTABLE_LLU(288230376151711737), PORTABLE_LLU(288230376151711739), PORTABLE_LLU(288230376151711741), PORTABLE_LLU(288230376151711743), // 2^58 PORTABLE_LLU(576460752303423479), PORTABLE_LLU(576460752303423481), PORTABLE_LLU(576460752303423483), PORTABLE_LLU(576460752303423485), PORTABLE_LLU(576460752303423487), // 2^59 PORTABLE_LLU(1152921504606846967), PORTABLE_LLU(1152921504606846969), PORTABLE_LLU(1152921504606846971), PORTABLE_LLU(1152921504606846973), PORTABLE_LLU(1152921504606846975), // 2^60 PORTABLE_LLU(2305843009213693941), PORTABLE_LLU(2305843009213693943), PORTABLE_LLU(2305843009213693945), PORTABLE_LLU(2305843009213693947), PORTABLE_LLU(2305843009213693949), // 2^61 PORTABLE_LLU(4611686018427387895), PORTABLE_LLU(4611686018427387897), PORTABLE_LLU(4611686018427387899), PORTABLE_LLU(4611686018427387901), PORTABLE_LLU(4611686018427387903), // 2^62 PORTABLE_LLU(9223372036854775799), PORTABLE_LLU(9223372036854775801), PORTABLE_LLU(9223372036854775803), PORTABLE_LLU(9223372036854775805), PORTABLE_LLU(9223372036854775807) // 2^63 #endif }; #endif powerman-2.4.4/src/libczmq/zhashx.c000066400000000000000000001275771467035776500173210ustar00rootroot00000000000000/* ========================================================================= zhashx - extended generic hash container Copyright (c) the Contributors as noted in the AUTHORS file. This file is part of CZMQ, the high-level C binding for 0MQ: http://czmq.zeromq.org. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. ========================================================================= */ /* This is a copy of the czmq zhashx library. * * Due to czmq issue #2173 * (https://github.com/zeromq/czmq/issues/2173) a localized copy was * made instead of waiting for OS distros to pick up the bug fix. * * This file is a verbatim copy with only minor adjustments included * headers. */ /* @header zhashx is an extended hash table container with more functionality than zhash, its simpler cousin. @discuss The hash table always has a size that is prime and roughly doubles its size when 75% full. In case of hash collisions items are chained in a linked list. The hash table size is increased slightly (up to 5 times before roughly doubling the size) when an overly long chain (between 1 and 63 items depending on table size) is detected. @end */ #include "czmq.h" #include "czmq_internal.h" // Hash table performance parameters #define INITIAL_PRIME 0 // Initial size in items (index into primes) #define GROWTH_FACTOR 5 // Increase after splitting (index into primes) #define LOAD_FACTOR 75 // Percent loading before splitting #define INITIAL_CHAIN 1 // Initial chaining limit #define CHAIN_GROWS 1 // Increase after splitting (chaining limit) #include "zhash_primes.inc" // Hash item, used internally only typedef struct _item_t { void *value; // Opaque item value struct _item_t *next; // Next item in the hash slot size_t index; // Index of item in table const void *key; // Item's original key zhashx_free_fn *free_fn; // Value free function if any } item_t; // --------------------------------------------------------------------- // Structure of our class struct _zhashx_t { size_t size; // Current size of hash table uint prime_index; // Current prime number used as limit uint chain_limit; // Current limit on chain length item_t **items; // Array of items size_t cached_index; // Avoids duplicate hash calculations size_t cursor_index; // For first/next iteration item_t *cursor_item; // For first/next iteration const void *cursor_key; // After first/next call, points to key zlistx_t *comments; // File comments, if any time_t modified; // Set during zhashx_load char *filename; // Set during zhashx_load // Function callbacks for duplicating and destroying items, if any zhashx_duplicator_fn *duplicator; zhashx_destructor_fn *destructor; // Function callbacks for duplicating and destroying keys, if any zhashx_duplicator_fn *key_duplicator; zhashx_destructor_fn *key_destructor; zhashx_comparator_fn *key_comparator; // Custom hash function zhashx_hash_fn *hasher; }; // Local helper functions static item_t *s_item_lookup (zhashx_t *self, const void *key); static item_t *s_item_insert (zhashx_t *self, const void *key, void *value); static void s_item_destroy (zhashx_t *self, item_t *item, bool hard); // -------------------------------------------------------------------------- // Modified Bernstein hashing function static size_t s_bernstein_hash (const void *key) { const char *pointer = (const char *) key; size_t key_hash = 0; while (*pointer) key_hash = 33 * key_hash ^ *pointer++; return key_hash; } // -------------------------------------------------------------------------- // Hash table constructor zhashx_t * zhashx_new (void) { zhashx_t *self = (zhashx_t *) zmalloc (sizeof (zhashx_t)); assert (self); self->prime_index = INITIAL_PRIME; self->chain_limit = INITIAL_CHAIN; size_t limit = primes [self->prime_index]; self->items = (item_t **) zmalloc (sizeof (item_t *) * limit); assert (self->items); self->hasher = s_bernstein_hash; self->key_destructor = (zhashx_destructor_fn *) zstr_free; self->key_duplicator = (zhashx_duplicator_fn *) strdup; self->key_comparator = (zhashx_comparator_fn *) strcmp; return self; } // -------------------------------------------------------------------------- // Purge all items from a hash table static void s_purge (zhashx_t *self) { uint index; size_t limit = primes [self->prime_index]; for (index = 0; index < limit; index++) { // Destroy all items in this hash bucket item_t *cur_item = self->items [index]; while (cur_item) { item_t *next_item = cur_item->next; s_item_destroy (self, cur_item, true); cur_item = next_item; } self->items [index] = NULL; } } // -------------------------------------------------------------------------- // Hash table destructor void zhashx_destroy (zhashx_t **self_p) { assert (self_p); if (*self_p) { zhashx_t *self = *self_p; if (self->items) { s_purge (self); freen (self->items); } zlistx_destroy (&self->comments); freen (self->filename); freen (self); *self_p = NULL; } } // -------------------------------------------------------------------------- // Local helper function // Destroy item in hash table, item must exist in table static void s_item_destroy (zhashx_t *self, item_t *item, bool hard) { // Find previous item since it's a singly-linked list item_t *cur_item = self->items [item->index]; item_t **prev_item = &(self->items [item->index]); while (cur_item) { if (cur_item == item) break; prev_item = &(cur_item->next); cur_item = cur_item->next; } assert (cur_item); *prev_item = item->next; self->size--; if (hard) { if (self->destructor) (self->destructor)(&item->value); else if (item->free_fn) (item->free_fn)(item->value); self->cursor_item = NULL; self->cursor_key = NULL; if (self->key_destructor) (self->key_destructor)((void **) &item->key); freen (item); } } // -------------------------------------------------------------------------- // Rehash hash table with specified new prime index // Returns 0 on success, or fails the assertions (e.g. insufficient memory) // Note: Older code used to return -1 in case of errors - this is no longer so static int s_zhashx_rehash (zhashx_t *self, uint new_prime_index) { assert (self); assert (new_prime_index < sizeof (primes)); size_t limit = primes [self->prime_index]; size_t new_limit = primes [new_prime_index]; item_t **new_items = (item_t **) zmalloc (sizeof (item_t *) * new_limit); assert (new_items); // Move all items to the new hash table, rehashing to // take into account new hash table limit size_t index; for (index = 0; index < limit; index++) { item_t *cur_item = self->items [index]; while (cur_item) { item_t *next_item = cur_item->next; size_t new_index = self->hasher (cur_item->key); new_index %= new_limit; cur_item->index = new_index; cur_item->next = new_items [new_index]; new_items [new_index] = cur_item; cur_item = next_item; } } // Destroy old hash table freen (self->items); self->items = new_items; self->prime_index = new_prime_index; return 0; } // -------------------------------------------------------------------------- // Insert item into hash table with specified key and item. Returns 0 on // success. If the key is already present, returns -1 and leaves existing // item unchanged. Sets the hash cursor to the item, if found. Dies with // assertion if the process heap memory ran out. (Note: older code returned // -1 in such cases; this is no longer so). int zhashx_insert (zhashx_t *self, const void *key, void *value) { assert (self); assert (key); // If we're exceeding the load factor of the hash table, // resize it according to the growth factor size_t limit = primes [self->prime_index]; if (self->size >= limit * LOAD_FACTOR / 100) { // Create new hash table uint new_prime_index = self->prime_index + GROWTH_FACTOR; assert (s_zhashx_rehash (self, new_prime_index) == 0); self->chain_limit += CHAIN_GROWS; } return s_item_insert (self, key, value)? 0: -1; } // -------------------------------------------------------------------------- // Local helper function // Insert new item into hash table, returns item // If item already existed, returns NULL // Sets the hash cursor to the item, if found. static item_t * s_item_insert (zhashx_t *self, const void *key, void *value) { // Check that item does not already exist in hash table // Leaves self->cached_index with calculated hash item item_t *item = s_item_lookup (self, key); if (item == NULL) { item = (item_t *) zmalloc (sizeof (item_t)); assert (item); // If necessary, take duplicate of item key if (self->key_duplicator) item->key = (self->key_duplicator)((void *) key); else item->key = key; // If necessary, take duplicate of item value if (self->duplicator) item->value = (self->duplicator)(value); else item->value = value; item->index = self->cached_index; // Insert into start of bucket list item->next = self->items [self->cached_index]; self->items [self->cached_index] = item; self->size++; self->cursor_item = item; self->cursor_key = item->key; } else item = NULL; // Signal duplicate insertion return item; } // -------------------------------------------------------------------------- // Local helper function // Lookup item in hash table, returns item or NULL // Dies with assertion if the process heap memory ran out (Note: older code // returned NULL in such cases; this is no longer so). static item_t * s_item_lookup (zhashx_t *self, const void *key) { // Look in bucket list for item by key size_t limit = primes [self->prime_index]; self->cached_index = self->hasher (key) % limit; item_t *item = self->items [self->cached_index]; uint len = 0; while (item) { if ((self->key_comparator)(item->key, key) == 0) break; item = item->next; ++len; } if (len > self->chain_limit) { // Create new hash table uint new_prime_index = self->prime_index + GROWTH_FACTOR; assert (s_zhashx_rehash (self, new_prime_index) == 0); limit = primes [self->prime_index]; self->cached_index = self->hasher (key) % limit; self->chain_limit += CHAIN_GROWS; } return item; } // -------------------------------------------------------------------------- // Update or insert item into hash table with specified key and item. If the // key is already present, destroys old item and inserts new one. If you set // a container item destructor, this is called on the old value. If the key // was not already present, inserts a new item. Sets the hash cursor to the // new item. void zhashx_update (zhashx_t *self, const void *key, void *value) { assert (self); assert (key); item_t *item = s_item_lookup (self, key); if (item) { if (self->destructor) (self->destructor)(&item->value); else if (item->free_fn) (item->free_fn)(item->value); // If necessary, take duplicate of item value if (self->duplicator) item->value = (self->duplicator)(value); else item->value = value; } else zhashx_insert (self, key, value); } // -------------------------------------------------------------------------- // Remove an item specified by key from the hash table. If there was no such // item, this function does nothing. void zhashx_delete (zhashx_t *self, const void *key) { assert (self); assert (key); item_t *item = s_item_lookup (self, key); if (item) s_item_destroy (self, item, true); } // -------------------------------------------------------------------------- // Delete all items from the hash table. If the key destructor is // set, calls it on every key. If the item destructor is set, calls // it on every item. void zhashx_purge (zhashx_t *self) { assert (self); s_purge (self); if (self->prime_index > INITIAL_PRIME) { // Try to shrink hash table size_t limit = primes [INITIAL_PRIME]; item_t **items = (item_t **) zmalloc (sizeof (item_t *) * limit); assert (items); freen (self->items); self->prime_index = INITIAL_PRIME; self->chain_limit = INITIAL_CHAIN; self->items = items; } } // -------------------------------------------------------------------------- // Look for item in hash table and return its item, or NULL. Sets the hash // cursor to the item, if found. void * zhashx_lookup (zhashx_t *self, const void *key) { assert (self); assert (key); item_t *item = s_item_lookup (self, key); if (item) { self->cursor_item = item; self->cursor_key = item->key; return item->value; } else return NULL; } // -------------------------------------------------------------------------- // Reindexes an item from an old key to a new key. If there was no such // item, does nothing. If the new key already exists, deletes old item. // Sets the item cursor to the renamed item. int zhashx_rename (zhashx_t *self, const void *old_key, const void *new_key) { item_t *old_item = s_item_lookup (self, old_key); item_t *new_item = s_item_lookup (self, new_key); if (old_item && !new_item) { s_item_destroy (self, old_item, false); if (self->key_destructor) (self->key_destructor)((void **) &old_item->key); if (self->key_duplicator) old_item->key = (self->key_duplicator)(new_key); else old_item->key = new_key; old_item->index = self->cached_index; old_item->next = self->items [self->cached_index]; self->items [self->cached_index] = old_item; self->size++; self->cursor_item = old_item; self->cursor_key = old_item->key; return 0; } else return -1; } // -------------------------------------------------------------------------- // Set a free function for the specified hash table item. When the item is // destroyed, the free function, if any, is called on that item. // Use this when hash items are dynamically allocated, to ensure that // you don't have memory leaks. You can pass 'free' or NULL as a free_fn. // Returns the item, or NULL if there is no such item. void * zhashx_freefn (zhashx_t *self, const void *key, zhashx_free_fn free_fn) { assert (self); assert (key); item_t *item = s_item_lookup (self, key); if (item) { item->free_fn = free_fn; return item->value; } else return NULL; } // -------------------------------------------------------------------------- // Return size of hash table size_t zhashx_size (zhashx_t *self) { assert (self); return self->size; } // -------------------------------------------------------------------------- // Return a zlistx_t containing the keys for the items in the // table. Uses the key_duplicator to duplicate all keys and sets the // key_destructor as destructor for the list. zlistx_t * zhashx_keys (zhashx_t *self) { assert (self); zlistx_t *keys = zlistx_new (); if (!keys) return NULL; zlistx_set_destructor (keys, self->key_destructor); zlistx_set_duplicator (keys, self->key_duplicator); uint index; size_t limit = primes [self->prime_index]; for (index = 0; index < limit; index++) { item_t *item = self->items [index]; while (item) { if (zlistx_add_end (keys, (void *) item->key) == NULL) { zlistx_destroy (&keys); return NULL; } item = item->next; } } return keys; } // Return a zlistx_t containing the items in the table. If there exists // a duplicator, then it is used to duplicate all items, and if there // is a destructor then it set as the destructor for the list. zlistx_t * zhashx_values (zhashx_t *self) { assert (self); zlistx_t *values = zlistx_new (); if (!values) return NULL; zlistx_set_destructor (values, self->destructor); zlistx_set_duplicator (values, self->duplicator); uint index; size_t limit = primes [self->prime_index]; for (index = 0; index < limit; index++) { item_t *item = self->items [index]; while (item) { if (zlistx_add_end (values, (void *) item->value) == NULL) { zlistx_destroy (&values); return NULL; } item = item->next; } } return values; } // -------------------------------------------------------------------------- // Simple iterator; returns first item in hash table, in no given order, // or NULL if the table is empty. This method is simpler to use than the // foreach() method, which is deprecated. NOTE: do NOT modify the table // while iterating. void * zhashx_first (zhashx_t *self) { assert (self); // Point to before or at first item self->cursor_index = 0; self->cursor_item = self->items [self->cursor_index]; // Now scan forwards to find it, leave cursor after item return zhashx_next (self); } // -------------------------------------------------------------------------- // Simple iterator; returns next item in hash table, in no given order, // or NULL if the last item was already returned. Use this together with // zhashx_first() to process all items in a hash table. If you need the // items in sorted order, use zhashx_keys() and then zlistx_sort(). NOTE: // do NOT modify the table while iterating. void * zhashx_next (zhashx_t *self) { assert (self); // Scan forward from cursor until we find an item size_t limit = primes [self->prime_index]; while (self->cursor_item == NULL) { if (self->cursor_index < limit - 1) self->cursor_index++; else return NULL; // At end of table // Get first item in next bucket self->cursor_item = self->items [self->cursor_index]; } // We have an item, so return it, and bump past it assert (self->cursor_item); item_t *item = self->cursor_item; self->cursor_key = item->key; self->cursor_item = self->cursor_item->next; return item->value; } // -------------------------------------------------------------------------- // After a successful insert, update, or first/next method, returns the key // for the item that was returned. You may not modify or deallocate // the key, and it lasts as long as the item in the hash. // After an unsuccessful first/next, returns NULL. const void * zhashx_cursor (zhashx_t *self) { assert (self); return self->cursor_key; } #ifdef CZMQ_BUILD_EXTRA // -------------------------------------------------------------------------- // Add a comment to hash table before saving to disk. You can add as many // comment lines as you like. These comment lines are discarded when loading // the file. If you use a null format, all comments are deleted. // FIXME: return 0 on success, -1 on error void zhashx_comment (zhashx_t *self, const char *format, ...) { if (format) { if (!self->comments) { self->comments = zlistx_new (); if (!self->comments) return; zlistx_set_destructor (self->comments, (zhashx_destructor_fn *) zstr_free); } va_list argptr; va_start (argptr, format); char *string = zsys_vprintf (format, argptr); va_end (argptr); if (string) zlistx_add_end (self->comments, string); } else zlistx_destroy (&self->comments); } // -------------------------------------------------------------------------- // Save hash table to a text file in name=value format // Hash values must be printable strings. // Returns 0 if OK, else -1 if a file error occurred int zhashx_save (zhashx_t *self, const char *filename) { assert (self); FILE *handle = fopen (filename, "w"); if (!handle) return -1; // Failed to create file if (self->comments) { char *comment = (char *) zlistx_first (self->comments); while (comment) { fprintf (handle, "# %s\n", comment); comment = (char *) zlistx_next (self->comments); } fprintf (handle, "\n"); } uint index; size_t limit = primes [self->prime_index]; for (index = 0; index < limit; index++) { item_t *item = self->items [index]; while (item) { fprintf (handle, "%s=%s\n", (char *) item->key, (char *) item->value); item = item->next; } } fclose (handle); return 0; } // -------------------------------------------------------------------------- // Load hash table from a text file in name=value format; hash table must // already exist. Hash values must printable strings. // Returns 0 if OK, else -1 if a file was not readable. int zhashx_load (zhashx_t *self, const char *filename) { assert (self); zhashx_set_destructor (self, (zhashx_destructor_fn *) zstr_free); zhashx_set_duplicator (self, (zhashx_duplicator_fn *) strdup); // Whether or not file exists, we'll track the filename and last // modification date (0 for unknown files), so that zhashx_refresh () // will always work after zhashx_load (), to load a newly-created // file. // Take copy of filename in case self->filename is same string. char *filename_copy = strdup (filename); assert (filename_copy); freen (self->filename); self->filename = filename_copy; self->modified = zsys_file_modified (self->filename); FILE *handle = fopen (self->filename, "r"); if (handle) { char *buffer = (char *) zmalloc (1024); assert (buffer); while (fgets (buffer, 1024, handle)) { // Skip lines starting with "#" or that do not look like // name=value data. char *equals = strchr (buffer, '='); if (buffer [0] == '#' || equals == buffer || !equals) continue; // Buffer may end in newline, which we don't want if (buffer [strlen (buffer) - 1] == '\n') buffer [strlen (buffer) - 1] = 0; *equals++ = 0; zhashx_update (self, buffer, equals); } freen (buffer); fclose (handle); } else return -1; // Failed to open file for reading return 0; } // -------------------------------------------------------------------------- // When a hash table was loaded from a file by zhashx_load, this method will // reload the file if it has been modified since, and is "stable", i.e. not // still changing. Returns 0 if OK, -1 if there was an error reloading the // file. int zhashx_refresh (zhashx_t *self) { assert (self); if (self->filename) { if (zsys_file_modified (self->filename) > self->modified && zsys_file_stable (self->filename)) { // Empty the hash table; code is copied from zhashx_destroy uint index; size_t limit = primes [self->prime_index]; for (index = 0; index < limit; index++) { // Destroy all items in this hash bucket item_t *cur_item = self->items [index]; while (cur_item) { item_t *next_item = cur_item->next; s_item_destroy (self, cur_item, true); cur_item = next_item; } } zhashx_load (self, self->filename); } } return 0; } // -------------------------------------------------------------------------- // Same as pack but uses a user-defined serializer function to convert items // into longstr. // Caller owns return value and must destroy it when done. zframe_t * zhashx_pack_own (zhashx_t *self, zhashx_serializer_fn serializer) { assert (self); // First, calculate packed data size size_t frame_size = 4; // Dictionary size, number-4 uint index; uint vindex = 0; size_t limit = primes [self->prime_index]; char **values = (char **) zmalloc (self->size * sizeof (char*)); for (index = 0; index < limit; index++) { item_t *item = self->items [index]; while (item) { // We store key as short string frame_size += 1 + strlen ((char *) item->key); // We store value as long string if (serializer != NULL) values [vindex] = serializer (item->value); else values [vindex] = (char *) item->value; frame_size += 4 + strlen ((char *) values [vindex]); item = item->next; vindex++; } } // Now serialize items into the frame zframe_t *frame = zframe_new (NULL, frame_size); if (!frame) { freen (values); return NULL; } byte *needle = zframe_data (frame); // Store size as number-4 *(uint32_t *) needle = htonl ((u_long) self->size); needle += 4; vindex = 0; for (index = 0; index < limit; index++) { item_t *item = self->items [index]; while (item) { // Store key as string size_t length = strlen ((char *) item->key); *needle++ = (byte) length; memcpy (needle, item->key, length); needle += length; // Store value as longstr length = strlen (values [vindex]); uint32_t serialize = htonl ((u_long) length); memcpy (needle, &serialize, 4); needle += 4; memcpy (needle, values [vindex], length); needle += length; item = item->next; // Destroy serialized value if (serializer != NULL) zstr_free (&values [vindex]); vindex++; } } freen (values); return frame; } // -------------------------------------------------------------------------- // Serialize hash table to a binary frame that can be sent in a message. // The packed format is compatible with the 'dictionary' type defined in // http://rfc.zeromq.org/spec:35/FILEMQ, and implemented by zproto: // // ; A list of name/value pairs // dictionary = dict-count *( dict-name dict-value ) // dict-count = number-4 // dict-value = longstr // dict-name = string // // ; Strings are always length + text contents // longstr = number-4 *VCHAR // string = number-1 *VCHAR // // ; Numbers are unsigned integers in network byte order // number-1 = 1OCTET // number-4 = 4OCTET // // Comments are not included in the packed data. Item values MUST be // strings. zframe_t * zhashx_pack (zhashx_t *self) { return zhashx_pack_own (self, NULL); } // -------------------------------------------------------------------------- // Same as unpack but uses a user-defined deserializer function to convert // a longstr back into item format. zhashx_t * zhashx_unpack_own (zframe_t *frame, zhashx_deserializer_fn deserializer) { zhashx_t *self = zhashx_new (); if (!self) return NULL; // Hash will free values in destructor zhashx_set_destructor (self, (zhashx_destructor_fn *) zstr_free); assert (frame); if (zframe_size (frame) < 4) return self; // Arguable... byte *needle = zframe_data (frame); byte *ceiling = needle + zframe_size (frame); size_t nbr_items = ntohl (*(uint32_t *) needle); needle += 4; while (nbr_items && needle < ceiling) { // Get key as string size_t key_size = *needle++; if (needle + key_size <= ceiling) { char key [256]; memcpy (key, needle, key_size); key [key_size] = 0; needle += key_size; // Get value as longstr if (needle + 4 <= ceiling) { size_t value_size = ntohl (*(uint32_t *) needle); needle += 4; // Be wary of malformed frames if (needle + value_size <= ceiling) { char *value = (char *) zmalloc (value_size + 1); assert (value); memcpy (value, needle, value_size); value [value_size] = 0; needle += value_size; // Convert string to real value void *real_value; if (deserializer != NULL) { real_value = deserializer (value); zstr_free (&value); } else real_value = value; // Hash takes ownership of real_value if (zhashx_insert (self, key, real_value)) { zhashx_destroy (&self); break; } } } } } if (self) zhashx_set_duplicator (self, (zhashx_duplicator_fn *) strdup); return self; } // -------------------------------------------------------------------------- // Unpack binary frame into a new hash table. Packed data must follow format // defined by zhashx_pack. Hash table is set to autofree. An empty frame // unpacks to an empty hash table. zhashx_t * zhashx_unpack (zframe_t *frame) { return zhashx_unpack_own (frame, NULL); } #endif // CZMQ_BUILD_EXTRA // -------------------------------------------------------------------------- // Make a copy of the list; items are duplicated if you set a duplicator // for the list, otherwise not. Copying a null reference returns a null // reference. Note that this method's behavior changed slightly for CZMQ // v3.x, as it does not set nor respect autofree. It does however let you // duplicate any hash table safely. The old behavior is in zhashx_dup_v2. zhashx_t * zhashx_dup (zhashx_t *self) { if (!self) return NULL; zhashx_t *copy = zhashx_new (); if (copy) { copy->destructor = self->destructor; copy->duplicator = self->duplicator; copy->key_duplicator = self->key_duplicator; copy->key_destructor = self->key_destructor; copy->key_comparator = self->key_comparator; copy->hasher = self->hasher; uint index; size_t limit = primes [self->prime_index]; for (index = 0; index < limit; index++) { item_t *item = self->items [index]; while (item) { if (zhashx_insert (copy, item->key, item->value)) { zhashx_destroy (©); break; } item = item->next; } } } return copy; } // -------------------------------------------------------------------------- // Set a user-defined deallocator for hash items; by default items are not // freed when the hash is destroyed. void zhashx_set_destructor (zhashx_t *self, zhashx_destructor_fn destructor) { assert (self); self->destructor = destructor; } // -------------------------------------------------------------------------- // Set a user-defined duplicator for hash items; by default items are not // copied when the hash is duplicated. void zhashx_set_duplicator (zhashx_t *self, zhashx_duplicator_fn duplicator) { assert (self); self->duplicator = duplicator; } // -------------------------------------------------------------------------- // Set a user-defined deallocator for keys; by default keys are // freed when the hash is destroyed by calling free(). void zhashx_set_key_destructor (zhashx_t *self, zhashx_destructor_fn destructor) { assert (self); self->key_destructor = destructor; } // -------------------------------------------------------------------------- // Set a user-defined duplicator for keys; by default keys are // duplicated by calling strdup(). void zhashx_set_key_duplicator (zhashx_t *self, zhashx_duplicator_fn duplicator) { assert (self); self->key_duplicator = duplicator; } // -------------------------------------------------------------------------- // Set a user-defined comparator for keys; by default keys are // compared using streq. void zhashx_set_key_comparator (zhashx_t *self, zhashx_comparator_fn comparator) { assert (self); assert (comparator != NULL); self->key_comparator = comparator; } // -------------------------------------------------------------------------- // Set a user-defined hash function for keys; by default keys are // hashed by a modified Bernstein hashing function. void zhashx_set_key_hasher (zhashx_t *self, zhashx_hash_fn hasher) { assert (self); self->hasher = hasher; } // -------------------------------------------------------------------------- // DEPRECATED by zhashx_dup // Make copy of hash table; if supplied table is null, returns null. // Does not copy items themselves. Rebuilds new table so may be slow on // very large tables. NOTE: only works with item values that are strings // since there's no other way to know how to duplicate the item value. zhashx_t * zhashx_dup_v2 (zhashx_t *self) { if (!self) return NULL; zhashx_t *copy = zhashx_new (); if (copy) { zhashx_set_destructor (copy, (zhashx_destructor_fn *) zstr_free); zhashx_set_duplicator (copy, (zhashx_duplicator_fn *) strdup); uint index; size_t limit = primes [self->prime_index]; for (index = 0; index < limit; index++) { item_t *item = self->items [index]; while (item) { if (zhashx_insert (copy, item->key, item->value)) { zhashx_destroy (©); break; } item = item->next; } } } return copy; } #ifdef CZMQ_BUILD_EXTRA // -------------------------------------------------------------------------- // Runs selftest of class // #ifdef CZMQ_BUILD_DRAFT_API static char * s_test_serialize_int (const void *item) { int *int_item = (int *) item; char *str_item = (char *) zmalloc (sizeof (char) * 10); sprintf (str_item, "%d", *int_item); return str_item; } static void * s_test_deserialze_int (const char *str_item) { int *int_item = (int *) zmalloc (sizeof (int)); sscanf (str_item, "%d", int_item); return int_item; } static void s_test_destroy_int (void **item) { int *int_item = (int *) *item; freen (int_item); } #endif // CZMQ_BUILD_DRAFT_API void zhashx_test (bool verbose) { printf (" * zhashx: "); // @selftest zhashx_t *hash = zhashx_new (); assert (hash); assert (zhashx_size (hash) == 0); assert (zhashx_first (hash) == NULL); assert (zhashx_cursor (hash) == NULL); // Insert some items int rc; rc = zhashx_insert (hash, "DEADBEEF", "dead beef"); char *item = (char *) zhashx_first (hash); assert (streq ((char *) zhashx_cursor (hash), "DEADBEEF")); assert (streq (item, "dead beef")); assert (rc == 0); rc = zhashx_insert (hash, "ABADCAFE", "a bad cafe"); assert (rc == 0); rc = zhashx_insert (hash, "C0DEDBAD", "coded bad"); assert (rc == 0); rc = zhashx_insert (hash, "DEADF00D", "dead food"); assert (rc == 0); assert (zhashx_size (hash) == 4); // Look for existing items item = (char *) zhashx_lookup (hash, "DEADBEEF"); assert (streq (item, "dead beef")); item = (char *) zhashx_lookup (hash, "ABADCAFE"); assert (streq (item, "a bad cafe")); item = (char *) zhashx_lookup (hash, "C0DEDBAD"); assert (streq (item, "coded bad")); item = (char *) zhashx_lookup (hash, "DEADF00D"); assert (streq (item, "dead food")); // Look for non-existent items item = (char *) zhashx_lookup (hash, "foo"); assert (item == NULL); // Try to insert duplicate items rc = zhashx_insert (hash, "DEADBEEF", "foo"); assert (rc == -1); item = (char *) zhashx_lookup (hash, "DEADBEEF"); assert (streq (item, "dead beef")); // Some rename tests // Valid rename, key is now LIVEBEEF rc = zhashx_rename (hash, "DEADBEEF", "LIVEBEEF"); assert (rc == 0); item = (char *) zhashx_lookup (hash, "LIVEBEEF"); assert (streq (item, "dead beef")); // Trying to rename an unknown item to a non-existent key rc = zhashx_rename (hash, "WHATBEEF", "NONESUCH"); assert (rc == -1); // Trying to rename an unknown item to an existing key rc = zhashx_rename (hash, "WHATBEEF", "LIVEBEEF"); assert (rc == -1); item = (char *) zhashx_lookup (hash, "LIVEBEEF"); assert (streq (item, "dead beef")); // Trying to rename an existing item to another existing item rc = zhashx_rename (hash, "LIVEBEEF", "ABADCAFE"); assert (rc == -1); item = (char *) zhashx_lookup (hash, "LIVEBEEF"); assert (streq (item, "dead beef")); item = (char *) zhashx_lookup (hash, "ABADCAFE"); assert (streq (item, "a bad cafe")); // Test keys method zlistx_t *keys = zhashx_keys (hash); assert (zlistx_size (keys) == 4); zlistx_destroy (&keys); zlistx_t *values = zhashx_values (hash); assert (zlistx_size (values) == 4); zlistx_destroy (&values); // Test dup method zhashx_t *copy = zhashx_dup (hash); assert (zhashx_size (copy) == 4); item = (char *) zhashx_lookup (copy, "LIVEBEEF"); assert (item); assert (streq (item, "dead beef")); zhashx_destroy (©); // Test pack/unpack methods zframe_t *frame = zhashx_pack (hash); copy = zhashx_unpack (frame); zframe_destroy (&frame); assert (zhashx_size (copy) == 4); item = (char *) zhashx_lookup (copy, "LIVEBEEF"); assert (item); assert (streq (item, "dead beef")); zhashx_destroy (©); #ifdef CZMQ_BUILD_DRAFT_API // Test own pack/unpack methods zhashx_t *own_hash = zhashx_new (); zhashx_set_destructor (own_hash, s_test_destroy_int); assert (own_hash); int *val1 = (int *) zmalloc (sizeof (int)); int *val2 = (int *) zmalloc (sizeof (int)); *val1 = 25; *val2 = 100; zhashx_insert (own_hash, "val1", val1); zhashx_insert (own_hash, "val2", val2); frame = zhashx_pack_own (own_hash, s_test_serialize_int); copy = zhashx_unpack_own (frame, s_test_deserialze_int); zhashx_set_destructor (copy, s_test_destroy_int); zframe_destroy (&frame); assert (zhashx_size (copy) == 2); assert (*((int *) zhashx_lookup (copy, "val1")) == 25); assert (*((int *) zhashx_lookup (copy, "val2")) == 100); zhashx_destroy (©); zhashx_destroy (&own_hash); #endif // CZMQ_BUILD_DRAFT_API // Test save and load zhashx_comment (hash, "This is a test file"); zhashx_comment (hash, "Created by %s", "czmq_selftest"); zhashx_save (hash, ".cache"); copy = zhashx_new (); assert (copy); zhashx_load (copy, ".cache"); item = (char *) zhashx_lookup (copy, "LIVEBEEF"); assert (item); assert (streq (item, "dead beef")); zhashx_destroy (©); zsys_file_delete (".cache"); // Delete a item zhashx_delete (hash, "LIVEBEEF"); item = (char *) zhashx_lookup (hash, "LIVEBEEF"); assert (item == NULL); assert (zhashx_size (hash) == 3); // Check that the queue is robust against random usage struct { char name [100]; bool exists; } testset [200]; memset (testset, 0, sizeof (testset)); int testmax = 200, testnbr, iteration; srandom ((unsigned) time (NULL)); for (iteration = 0; iteration < 25000; iteration++) { testnbr = randof (testmax); assert (testnbr != testmax); assert (testnbr < testmax); if (testset [testnbr].exists) { item = (char *) zhashx_lookup (hash, testset [testnbr].name); assert (item); zhashx_delete (hash, testset [testnbr].name); testset [testnbr].exists = false; } else { sprintf (testset [testnbr].name, "%x-%x", rand (), rand ()); if (zhashx_insert (hash, testset [testnbr].name, "") == 0) testset [testnbr].exists = true; } } // Test 10K lookups for (iteration = 0; iteration < 10000; iteration++) item = (char *) zhashx_lookup (hash, "DEADBEEFABADCAFE"); // Destructor should be safe to call twice zhashx_destroy (&hash); zhashx_destroy (&hash); assert (hash == NULL); // Test randof() limits - should be within (0..testmax) // and randomness distribution - should not have (many) zero-counts // If there are - maybe the ZSYS_RANDOF_MAX is too big for this platform // Note: This test can take a while on systems with weak floating point HW testmax = 999; size_t rndcnt[999]; assert ((sizeof (rndcnt)/sizeof(rndcnt[0])) == testmax); memset (rndcnt, 0, sizeof (rndcnt)); for (iteration = 0; iteration < 10000000; iteration++) { testnbr = randof (testmax); assert (testnbr != testmax); assert (testnbr < testmax); assert (testnbr >= 0); rndcnt[testnbr]++; } int rndmisses = 0; for (iteration = 0; iteration < testmax; iteration++) { if (rndcnt[iteration] == 0) { zsys_warning("zhashx_test() : random distribution fault : got 0 hits for %d/%d", iteration, testmax); rndmisses++; } } // Too many misses are suspicious... we can lose half the entries // for each bit not used in the assumed ZSYS_RANDOF_MAX... assert ( (rndmisses < (testmax / 3 )) ); // Test destructor; automatically copies and frees string values hash = zhashx_new (); assert (hash); zhashx_set_destructor (hash, (zhashx_destructor_fn *) zstr_free); zhashx_set_duplicator (hash, (zhashx_duplicator_fn *) strdup); char value [255]; strcpy (value, "This is a string"); rc = zhashx_insert (hash, "key1", value); assert (rc == 0); strcpy (value, "Ring a ding ding"); rc = zhashx_insert (hash, "key2", value); assert (rc == 0); assert (streq ((char *) zhashx_lookup (hash, "key1"), "This is a string")); assert (streq ((char *) zhashx_lookup (hash, "key2"), "Ring a ding ding")); zhashx_destroy (&hash); // Test purger and shrinker: no data should end up unreferenced in valgrind hash = zhashx_new (); assert (hash); zhashx_set_destructor (hash, (zhashx_destructor_fn *) zstr_free); zhashx_set_duplicator (hash, (zhashx_duplicator_fn *) strdup); char valuep [255]; strcpy (valuep, "This is a string"); rc = zhashx_insert (hash, "key1", valuep); assert (rc == 0); strcpy (valuep, "Ring a ding ding"); rc = zhashx_insert (hash, "key2", valuep); assert (rc == 0); strcpy (valuep, "Cartahena delenda est"); rc = zhashx_insert (hash, "key3", valuep); assert (rc == 0); strcpy (valuep, "So say we all!"); rc = zhashx_insert (hash, "key4", valuep); assert (rc == 0); assert (streq ((char *) zhashx_lookup (hash, "key1"), "This is a string")); assert (streq ((char *) zhashx_lookup (hash, "key2"), "Ring a ding ding")); assert (streq ((char *) zhashx_lookup (hash, "key3"), "Cartahena delenda est")); assert (streq ((char *) zhashx_lookup (hash, "key4"), "So say we all!")); zhashx_purge (hash); zhashx_destroy (&hash); #if defined (__WINDOWS__) zsys_shutdown(); #endif // @end printf ("OK\n"); } #endif // CZMQ_BUILD_EXTRA powerman-2.4.4/src/libczmq/zhashx.h000066400000000000000000000262421467035776500173110ustar00rootroot00000000000000/* ========================================================================= zhashx - extended generic type-free hash container Copyright (c) the Contributors as noted in the AUTHORS file. This file is part of CZMQ, the high-level C binding for 0MQ: http://czmq.zeromq.org. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. ========================================================================= */ /* This is a copy of the czmq zhashx library. * * Due to czmq issue #2173 * (https://github.com/zeromq/czmq/issues/2173) a localized copy was * made instead of waiting for OS distros to pick up the bug fix. * * This file is a verbatim copy with only minor adjustments to header * guards and included headers. */ #ifndef __FLUXZHASHX_H_INCLUDED__ #define __FLUXZHASHX_H_INCLUDED__ #ifdef __cplusplus extern "C" { #endif // @warning THE FOLLOWING @INTERFACE BLOCK IS AUTO-GENERATED BY ZPROJECT // @warning Please edit the model at "api/zhashx.api" to make changes. // @interface // This is a stable class, and may not change except for emergencies. It // is provided in stable builds. // This class has draft methods, which may change over time. They are not // in stable releases, by default. Use --enable-drafts to enable. // Destroy an item typedef void (zhashx_destructor_fn) ( void **item); // Duplicate an item typedef void * (zhashx_duplicator_fn) ( const void *item); // Compare two items, for sorting typedef int (zhashx_comparator_fn) ( const void *item1, const void *item2); // Destroy an item. typedef void (zhashx_free_fn) ( void *data); // Hash function for keys. typedef size_t (zhashx_hash_fn) ( const void *key); // Serializes an item to a longstr. // The caller takes ownership of the newly created object. typedef char * (zhashx_serializer_fn) ( const void *item); // Deserializes a longstr into an item. // The caller takes ownership of the newly created object. typedef void * (zhashx_deserializer_fn) ( const char *item_str); // Create a new, empty hash container CZMQ_EXPORT zhashx_t * zhashx_new (void); #ifdef CZMQ_BUILD_EXTRA // Unpack binary frame into a new hash table. Packed data must follow format // defined by zhashx_pack. Hash table is set to autofree. An empty frame // unpacks to an empty hash table. CZMQ_EXPORT zhashx_t * zhashx_unpack (zframe_t *frame); #endif // CZMQ_BUILD_EXTRA // Destroy a hash container and all items in it CZMQ_EXPORT void zhashx_destroy (zhashx_t **self_p); // Insert item into hash table with specified key and item. // If key is already present returns -1 and leaves existing item unchanged // Returns 0 on success. CZMQ_EXPORT int zhashx_insert (zhashx_t *self, const void *key, void *item); // Update or insert item into hash table with specified key and item. If the // key is already present, destroys old item and inserts new one. If you set // a container item destructor, this is called on the old value. If the key // was not already present, inserts a new item. Sets the hash cursor to the // new item. CZMQ_EXPORT void zhashx_update (zhashx_t *self, const void *key, void *item); // Remove an item specified by key from the hash table. If there was no such // item, this function does nothing. CZMQ_EXPORT void zhashx_delete (zhashx_t *self, const void *key); // Delete all items from the hash table. If the key destructor is // set, calls it on every key. If the item destructor is set, calls // it on every item. CZMQ_EXPORT void zhashx_purge (zhashx_t *self); // Return the item at the specified key, or null CZMQ_EXPORT void * zhashx_lookup (zhashx_t *self, const void *key); // Reindexes an item from an old key to a new key. If there was no such // item, does nothing. Returns 0 if successful, else -1. CZMQ_EXPORT int zhashx_rename (zhashx_t *self, const void *old_key, const void *new_key); // Set a free function for the specified hash table item. When the item is // destroyed, the free function, if any, is called on that item. // Use this when hash items are dynamically allocated, to ensure that // you don't have memory leaks. You can pass 'free' or NULL as a free_fn. // Returns the item, or NULL if there is no such item. CZMQ_EXPORT void * zhashx_freefn (zhashx_t *self, const void *key, zhashx_free_fn free_fn); // Return the number of keys/items in the hash table CZMQ_EXPORT size_t zhashx_size (zhashx_t *self); // Return a zlistx_t containing the keys for the items in the // table. Uses the key_duplicator to duplicate all keys and sets the // key_destructor as destructor for the list. // Caller owns return value and must destroy it when done. CZMQ_EXPORT zlistx_t * zhashx_keys (zhashx_t *self); // Return a zlistx_t containing the values for the items in the // table. Uses the duplicator to duplicate all items and sets the // destructor as destructor for the list. // Caller owns return value and must destroy it when done. CZMQ_EXPORT zlistx_t * zhashx_values (zhashx_t *self); // Simple iterator; returns first item in hash table, in no given order, // or NULL if the table is empty. This method is simpler to use than the // foreach() method, which is deprecated. To access the key for this item // use zhashx_cursor(). NOTE: do NOT modify the table while iterating. CZMQ_EXPORT void * zhashx_first (zhashx_t *self); // Simple iterator; returns next item in hash table, in no given order, // or NULL if the last item was already returned. Use this together with // zhashx_first() to process all items in a hash table. If you need the // items in sorted order, use zhashx_keys() and then zlistx_sort(). To // access the key for this item use zhashx_cursor(). NOTE: do NOT modify // the table while iterating. CZMQ_EXPORT void * zhashx_next (zhashx_t *self); // After a successful first/next method, returns the key for the item that // was returned. This is a constant string that you may not modify or // deallocate, and which lasts as long as the item in the hash. After an // unsuccessful first/next, returns NULL. CZMQ_EXPORT const void * zhashx_cursor (zhashx_t *self); #ifdef CZMQ_BUILD_EXTRA // Add a comment to hash table before saving to disk. You can add as many // comment lines as you like. These comment lines are discarded when loading // the file. If you use a null format, all comments are deleted. CZMQ_EXPORT void zhashx_comment (zhashx_t *self, const char *format, ...) CHECK_PRINTF (2); // Save hash table to a text file in name=value format. Hash values must be // printable strings; keys may not contain '=' character. Returns 0 if OK, // else -1 if a file error occurred. CZMQ_EXPORT int zhashx_save (zhashx_t *self, const char *filename); // Load hash table from a text file in name=value format; hash table must // already exist. Hash values must printable strings; keys may not contain // '=' character. Returns 0 if OK, else -1 if a file was not readable. CZMQ_EXPORT int zhashx_load (zhashx_t *self, const char *filename); // When a hash table was loaded from a file by zhashx_load, this method will // reload the file if it has been modified since, and is "stable", i.e. not // still changing. Returns 0 if OK, -1 if there was an error reloading the // file. CZMQ_EXPORT int zhashx_refresh (zhashx_t *self); // Serialize hash table to a binary frame that can be sent in a message. // The packed format is compatible with the 'dictionary' type defined in // http://rfc.zeromq.org/spec:35/FILEMQ, and implemented by zproto: // // ; A list of name/value pairs // dictionary = dict-count *( dict-name dict-value ) // dict-count = number-4 // dict-value = longstr // dict-name = string // // ; Strings are always length + text contents // longstr = number-4 *VCHAR // string = number-1 *VCHAR // // ; Numbers are unsigned integers in network byte order // number-1 = 1OCTET // number-4 = 4OCTET // // Comments are not included in the packed data. Item values MUST be // strings. // Caller owns return value and must destroy it when done. CZMQ_EXPORT zframe_t * zhashx_pack (zhashx_t *self); #endif // CZMQ_BUILD_EXTRA // Make a copy of the list; items are duplicated if you set a duplicator // for the list, otherwise not. Copying a null reference returns a null // reference. Note that this method's behavior changed slightly for CZMQ // v3.x, as it does not set nor respect autofree. It does however let you // duplicate any hash table safely. The old behavior is in zhashx_dup_v2. // Caller owns return value and must destroy it when done. CZMQ_EXPORT zhashx_t * zhashx_dup (zhashx_t *self); // Set a user-defined deallocator for hash items; by default items are not // freed when the hash is destroyed. CZMQ_EXPORT void zhashx_set_destructor (zhashx_t *self, zhashx_destructor_fn destructor); // Set a user-defined duplicator for hash items; by default items are not // copied when the hash is duplicated. CZMQ_EXPORT void zhashx_set_duplicator (zhashx_t *self, zhashx_duplicator_fn duplicator); // Set a user-defined deallocator for keys; by default keys are freed // when the hash is destroyed using free(). CZMQ_EXPORT void zhashx_set_key_destructor (zhashx_t *self, zhashx_destructor_fn destructor); // Set a user-defined duplicator for keys; by default keys are duplicated // using strdup. CZMQ_EXPORT void zhashx_set_key_duplicator (zhashx_t *self, zhashx_duplicator_fn duplicator); // Set a user-defined comparator for keys; by default keys are // compared using strcmp. // The callback function should return zero (0) on matching // items. CZMQ_EXPORT void zhashx_set_key_comparator (zhashx_t *self, zhashx_comparator_fn comparator); // Set a user-defined hash function for keys; by default keys are // hashed by a modified Bernstein hashing function. CZMQ_EXPORT void zhashx_set_key_hasher (zhashx_t *self, zhashx_hash_fn hasher); // Make copy of hash table; if supplied table is null, returns null. // Does not copy items themselves. Rebuilds new table so may be slow on // very large tables. NOTE: only works with item values that are strings // since there's no other way to know how to duplicate the item value. CZMQ_EXPORT zhashx_t * zhashx_dup_v2 (zhashx_t *self); #ifdef CZMQ_BUILD_EXTRA // Self test of this class. CZMQ_EXPORT void zhashx_test (bool verbose); #ifdef CZMQ_BUILD_DRAFT_API // *** Draft method, for development use, may change without warning *** // Same as unpack but uses a user-defined deserializer function to convert // a longstr back into item format. CZMQ_EXPORT zhashx_t * zhashx_unpack_own (zframe_t *frame, zhashx_deserializer_fn deserializer); // *** Draft method, for development use, may change without warning *** // Same as pack but uses a user-defined serializer function to convert items // into longstr. // Caller owns return value and must destroy it when done. CZMQ_EXPORT zframe_t * zhashx_pack_own (zhashx_t *self, zhashx_serializer_fn serializer); #endif // CZMQ_BUILD_DRAFT_API #endif // CZMQ_BUILD_EXTRA // @end #ifdef __cplusplus } #endif #endif powerman-2.4.4/src/libczmq/zlist.c000066400000000000000000000420321467035776500171370ustar00rootroot00000000000000/* ========================================================================= zlist - simple generic list container Copyright (c) the Contributors as noted in the AUTHORS file. This file is part of CZMQ, the high-level C binding for 0MQ: http://czmq.zeromq.org. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. ========================================================================= */ /* @header Provides a generic container implementing a fast singly-linked list. You can use this to construct multi-dimensional lists, and other structures together with other generic containers like zhash. This is a simple class. For demanding applications we recommend using zlistx. @discuss To iterate through a list, use zlist_first to get the first item, then loop while not null, and do zlist_next at the end of each iteration. @end */ #include "czmq.h" #include "czmq_internal.h" // List node, used internally only typedef struct _node_t { struct _node_t *next; void *item; zlist_free_fn *free_fn; } node_t; // --------------------------------------------------------------------- // Structure of our class struct _zlist_t { node_t *head; // First item in list, if any node_t *tail; // Last item in list, if any node_t *cursor; // Current cursors for iteration size_t size; // Number of items in list bool autofree; // If true, free items in destructor zlist_compare_fn *compare_fn; // Function to compare two list item for // less than, equals or greater than }; // -------------------------------------------------------------------------- // List constructor zlist_t * zlist_new (void) { zlist_t *self = (zlist_t *) zmalloc (sizeof (zlist_t)); assert (self); return self; } // -------------------------------------------------------------------------- // List destructor void zlist_destroy (zlist_t **self_p) { assert (self_p); if (*self_p) { zlist_t *self = *self_p; zlist_purge (self); freen (self); *self_p = NULL; } } // -------------------------------------------------------------------------- // Return the item at the head of list. If the list is empty, returns NULL. // Leaves cursor pointing at the head item, or NULL if the list is empty. void * zlist_first (zlist_t *self) { assert (self); self->cursor = self->head; if (self->cursor) return self->cursor->item; else return NULL; } // -------------------------------------------------------------------------- // Return the next item. If the list is empty, returns NULL. To move to // the start of the list call zlist_first (). Advances the cursor. void * zlist_next (zlist_t *self) { assert (self); if (self->cursor) self->cursor = self->cursor->next; else self->cursor = self->head; if (self->cursor) return self->cursor->item; else return NULL; } // -------------------------------------------------------------------------- // Return the item at the tail of list. If the list is empty, returns NULL. // Leaves cursor pointing at the tail item, or NULL if the list is empty. void * zlist_last (zlist_t *self) { assert (self); self->cursor = self->tail; if (self->cursor) return self->cursor->item; else return NULL; } // -------------------------------------------------------------------------- // Return the item at the head of list. If the list is empty, returns NULL. // Leaves cursor as-is. void * zlist_head (zlist_t *self) { assert (self); return self->head? self->head->item: NULL; } // -------------------------------------------------------------------------- // Return the item at the tail of list. If the list is empty, returns NULL. // Leaves cursor as-is. void * zlist_tail (zlist_t *self) { assert (self); return self->tail? self->tail->item: NULL; } // -------------------------------------------------------------------------- // Return current item in the list. If the list is empty, or the cursor // passed the end of the list, returns NULL. Does not change the cursor. void * zlist_item (zlist_t *self) { assert (self); if (self->cursor) return self->cursor->item; else return NULL; } // -------------------------------------------------------------------------- // Append an item to the end of the list, return 0 if OK or -1 if this // failed for some reason. int zlist_append (zlist_t *self, void *item) { if (!item) return -1; node_t *node = (node_t *) zmalloc (sizeof (node_t)); assert (node); // If necessary, take duplicate of (string) item if (self->autofree) { item = strdup ((char *) item); assert (item); } node->item = item; if (self->tail) self->tail->next = node; else self->head = node; self->tail = node; node->next = NULL; self->size++; self->cursor = NULL; return 0; } // -------------------------------------------------------------------------- // Push an item to the start of the list, return 0 if OK or -1 if this // failed for some reason. int zlist_push (zlist_t *self, void *item) { if (!item) return -1; node_t *node = (node_t *) zmalloc (sizeof (node_t)); assert (node); // If necessary, take duplicate of (string) item if (self->autofree) { item = strdup ((char *) item); assert (item); } node->item = item; node->next = self->head; self->head = node; if (self->tail == NULL) self->tail = node; self->size++; self->cursor = NULL; return 0; } // -------------------------------------------------------------------------- // Remove item from the beginning of the list, returns NULL if none void * zlist_pop (zlist_t *self) { node_t *node = self->head; void *item = NULL; if (node) { item = node->item; self->head = node->next; if (self->tail == node) self->tail = NULL; freen (node); self->size--; } self->cursor = NULL; return item; } // -------------------------------------------------------------------------- // Checks if an item already is present. Uses compare method to determine if // items are equal. If the compare method is NULL the check will only compare // pointers. Returns true if item is present else false. bool zlist_exists (zlist_t *self, void *item) { assert (self); assert (item); node_t *node = self->head; while (node) { if (self->compare_fn) { if ((*self->compare_fn)(node->item, item) == 0) return true; } else if (node->item == item) return true; node = node->next; } return false; } // -------------------------------------------------------------------------- // Remove the item from the list, if present. Safe to call on items that // are not in the list. void zlist_remove (zlist_t *self, void *item) { node_t *node, *prev = NULL; // First off, we need to find the list node for (node = self->head; node != NULL; node = node->next) { if (self->compare_fn) { if ((*self->compare_fn)(node->item, item) == 0) break; } else if (node->item == item) break; prev = node; } if (node) { if (prev) prev->next = node->next; else self->head = node->next; if (node->next == NULL) self->tail = prev; if (self->cursor == node) self->cursor = prev; if (self->autofree) freen (node->item); else if (node->free_fn) (node->free_fn)(node->item); freen (node); self->size--; } } // -------------------------------------------------------------------------- // Make a copy of list. If the list has autofree set, the copied list will // duplicate all items, which must be strings. Otherwise, the list will hold // pointers back to the items in the original list. If list is null, returns // NULL. zlist_t * zlist_dup (zlist_t *self) { if (!self) return NULL; zlist_t *copy = zlist_new (); assert (copy); if (self->autofree) zlist_autofree(copy); copy->compare_fn = self->compare_fn; node_t *node; for (node = self->head; node; node = node->next) { if (zlist_append (copy, node->item) == -1) { zlist_destroy (©); break; } } return copy; } // -------------------------------------------------------------------------- // Purge all items from list void zlist_purge (zlist_t *self) { assert (self); node_t *node = self->head; while (node) { node_t *next = node->next; if (self->autofree) freen (node->item); else if (node->free_fn) (node->free_fn)(node->item); freen (node); node = next; } self->head = NULL; self->tail = NULL; self->cursor = NULL; self->size = 0; } // -------------------------------------------------------------------------- // Return the number of items in the list size_t zlist_size (zlist_t *self) { return self->size; } // -------------------------------------------------------------------------- // Sort the list. If the compare function is null, sorts the list by // ascending key value using a straight ASCII comparison. If you specify // a compare function, this decides how items are sorted. The sort is not // stable, so may reorder items with the same keys. The algorithm used is // combsort, a compromise between performance and simplicity. void zlist_sort (zlist_t *self, zlist_compare_fn compare_fn) { zlist_compare_fn *compare = compare_fn; if (!compare) { compare = self->compare_fn; if (!compare) compare = (zlist_compare_fn *) strcmp; } // Uses a comb sort, which is simple and reasonably fast. // See http://en.wikipedia.org/wiki/Comb_sort size_t gap = self->size; bool swapped = false; while (gap > 1 || swapped) { if (gap > 1) gap = (size_t) ((double) gap / 1.3); node_t *base = self->head; node_t *test = self->head; size_t jump = gap; while (jump--) test = test->next; swapped = false; while (base && test) { if ((*compare) (base->item, test->item) > 0) { // It's trivial to swap items in a generic container void *item = base->item; base->item = test->item; test->item = item; swapped = true; } base = base->next; test = test->next; } } } // -------------------------------------------------------------------------- // Sets a compare function for this list. The function compares two items. // It returns an integer less than, equal to, or greater than zero if the // first item is found, respectively, to be less than, to match, or be // greater than the second item. // This function is used for sorting, removal and exists checking. void zlist_comparefn (zlist_t *self, zlist_compare_fn fn) { assert (self); self->compare_fn = fn; } // -------------------------------------------------------------------------- // Set a free function for the specified list item. When the item is // destroyed, the free function, if any, is called on that item. // Use this when list items are dynamically allocated, to ensure that // you don't have memory leaks. You can pass 'free' or NULL as a free_fn. // Returns the item, or NULL if there is no such item. void * zlist_freefn (zlist_t *self, void *item, zlist_free_fn fn, bool at_tail) { node_t *node = self->head; if (at_tail) node = self->tail; while (node) { if (node->item == item) { node->free_fn = fn; return item; } node = node->next; } return NULL; } // -------------------------------------------------------------------------- // Set list for automatic item destruction; item values MUST be strings. // By default a list item refers to a value held elsewhere. When you set // this, each time you append or push a list item, zlist will take a copy // of the string value. Then, when you destroy the list, it will free all // item values automatically. If you use any other technique to allocate // list values, you must free them explicitly before destroying the list. // The usual technique is to pop list items and destroy them, until the // list is empty. void zlist_autofree (zlist_t *self) { assert (self); self->autofree = true; } #ifdef CZMQ_BUILD_EXTRA static void s_zlist_free (void *data) { zlist_t *self = (zlist_t *) data; zlist_destroy (&self); } // -------------------------------------------------------------------------- // Runs selftest of class void zlist_test (bool verbose) { printf (" * zlist: "); // @selftest zlist_t *list = zlist_new (); assert (list); assert (zlist_size (list) == 0); // Three items we'll use as test data // List items are void *, not particularly strings char *cheese = "boursin"; char *bread = "baguette"; char *wine = "bordeaux"; zlist_append (list, cheese); assert (zlist_size (list) == 1); assert ( zlist_exists (list, cheese)); assert (!zlist_exists (list, bread)); assert (!zlist_exists (list, wine)); zlist_append (list, bread); assert (zlist_size (list) == 2); assert ( zlist_exists (list, cheese)); assert ( zlist_exists (list, bread)); assert (!zlist_exists (list, wine)); zlist_append (list, wine); assert (zlist_size (list) == 3); assert ( zlist_exists (list, cheese)); assert ( zlist_exists (list, bread)); assert ( zlist_exists (list, wine)); assert (zlist_head (list) == cheese); assert (zlist_next (list) == cheese); assert (zlist_first (list) == cheese); assert (zlist_tail (list) == wine); assert (zlist_next (list) == bread); assert (zlist_first (list) == cheese); assert (zlist_next (list) == bread); assert (zlist_next (list) == wine); assert (zlist_next (list) == NULL); // After we reach end of list, next wraps around assert (zlist_next (list) == cheese); assert (zlist_size (list) == 3); zlist_remove (list, wine); assert (zlist_size (list) == 2); assert (zlist_first (list) == cheese); zlist_remove (list, cheese); assert (zlist_size (list) == 1); assert (zlist_first (list) == bread); zlist_remove (list, bread); assert (zlist_size (list) == 0); zlist_append (list, cheese); zlist_append (list, bread); assert (zlist_last (list) == bread); zlist_remove (list, bread); assert (zlist_last (list) == cheese); zlist_remove (list, cheese); assert (zlist_last (list) == NULL); zlist_push (list, cheese); assert (zlist_size (list) == 1); assert (zlist_first (list) == cheese); zlist_push (list, bread); assert (zlist_size (list) == 2); assert (zlist_first (list) == bread); assert (zlist_item (list) == bread); zlist_append (list, wine); assert (zlist_size (list) == 3); assert (zlist_first (list) == bread); zlist_t *sub_list = zlist_dup (list); assert (sub_list); assert (zlist_size (sub_list) == 3); zlist_sort (list, NULL); char *item; item = (char *) zlist_pop (list); assert (item == bread); item = (char *) zlist_pop (list); assert (item == wine); item = (char *) zlist_pop (list); assert (item == cheese); assert (zlist_size (list) == 0); assert (zlist_size (sub_list) == 3); zlist_push (list, sub_list); zlist_t *sub_list_2 = zlist_dup (sub_list); zlist_append (list, sub_list_2); assert (zlist_freefn (list, sub_list, &s_zlist_free, false) == sub_list); assert (zlist_freefn (list, sub_list_2, &s_zlist_free, true) == sub_list_2); zlist_destroy (&list); // Test autofree functionality list = zlist_new (); assert (list); zlist_autofree (list); // Set equals function otherwise equals will not work as autofree copies strings zlist_comparefn (list, (zlist_compare_fn *) strcmp); zlist_push (list, bread); zlist_append (list, cheese); assert (zlist_size (list) == 2); zlist_append (list, wine); assert (zlist_exists (list, wine)); zlist_remove (list, wine); assert (!zlist_exists (list, wine)); assert (streq ((const char *) zlist_first (list), bread)); item = (char *) zlist_pop (list); assert (streq (item, bread)); freen (item); item = (char *) zlist_pop (list); assert (streq (item, cheese)); freen (item); zlist_destroy (&list); assert (list == NULL); #if defined (__WINDOWS__) zsys_shutdown(); #endif // @end printf ("OK\n"); } #endif // CZMQ_BUILD_EXTRA powerman-2.4.4/src/libczmq/zlist.h000066400000000000000000000134721467035776500171520ustar00rootroot00000000000000/* ========================================================================= zlist - simple generic list container Copyright (c) the Contributors as noted in the AUTHORS file. This file is part of CZMQ, the high-level C binding for 0MQ: http://czmq.zeromq.org. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. ========================================================================= */ #ifndef __FLUX_ZLIST_H_INCLUDED__ #define __FLUX_ZLIST_H_INCLUDED__ #ifdef __cplusplus extern "C" { #endif // @warning THE FOLLOWING @INTERFACE BLOCK IS AUTO-GENERATED BY ZPROJECT // @warning Please edit the model at "api/zlist.api" to make changes. // @interface // This is a stable class, and may not change except for emergencies. It // is provided in stable builds. // Comparison function e.g. for sorting and removing. typedef int (zlist_compare_fn) ( void *item1, void *item2); // Callback function for zlist_freefn method typedef void (zlist_free_fn) ( void *data); // Create a new list container CZMQ_EXPORT zlist_t * zlist_new (void); // Destroy a list container CZMQ_EXPORT void zlist_destroy (zlist_t **self_p); // Return the item at the head of list. If the list is empty, returns NULL. // Leaves cursor pointing at the head item, or NULL if the list is empty. CZMQ_EXPORT void * zlist_first (zlist_t *self); // Return the next item. If the list is empty, returns NULL. To move to // the start of the list call zlist_first (). Advances the cursor. CZMQ_EXPORT void * zlist_next (zlist_t *self); // Return the item at the tail of list. If the list is empty, returns NULL. // Leaves cursor pointing at the tail item, or NULL if the list is empty. CZMQ_EXPORT void * zlist_last (zlist_t *self); // Return first item in the list, or null, leaves the cursor CZMQ_EXPORT void * zlist_head (zlist_t *self); // Return last item in the list, or null, leaves the cursor CZMQ_EXPORT void * zlist_tail (zlist_t *self); // Return the current item of list. If the list is empty, returns NULL. // Leaves cursor pointing at the current item, or NULL if the list is empty. CZMQ_EXPORT void * zlist_item (zlist_t *self); // Append an item to the end of the list, return 0 if OK or -1 if this // failed for some reason (out of memory). Note that if a duplicator has // been set, this method will also duplicate the item. CZMQ_EXPORT int zlist_append (zlist_t *self, void *item); // Push an item to the start of the list, return 0 if OK or -1 if this // failed for some reason (out of memory). Note that if a duplicator has // been set, this method will also duplicate the item. CZMQ_EXPORT int zlist_push (zlist_t *self, void *item); // Pop the item off the start of the list, if any CZMQ_EXPORT void * zlist_pop (zlist_t *self); // Checks if an item already is present. Uses compare method to determine if // items are equal. If the compare method is NULL the check will only compare // pointers. Returns true if item is present else false. CZMQ_EXPORT bool zlist_exists (zlist_t *self, void *item); // Remove the specified item from the list if present CZMQ_EXPORT void zlist_remove (zlist_t *self, void *item); // Make a copy of list. If the list has autofree set, the copied list will // duplicate all items, which must be strings. Otherwise, the list will hold // pointers back to the items in the original list. If list is null, returns // NULL. // Caller owns return value and must destroy it when done. CZMQ_EXPORT zlist_t * zlist_dup (zlist_t *self); // Purge all items from list CZMQ_EXPORT void zlist_purge (zlist_t *self); // Return number of items in the list CZMQ_EXPORT size_t zlist_size (zlist_t *self); // Sort the list. If the compare function is null, sorts the list by // ascending key value using a straight ASCII comparison. If you specify // a compare function, this decides how items are sorted. The sort is not // stable, so may reorder items with the same keys. The algorithm used is // combsort, a compromise between performance and simplicity. CZMQ_EXPORT void zlist_sort (zlist_t *self, zlist_compare_fn compare); // Set list for automatic item destruction; item values MUST be strings. // By default a list item refers to a value held elsewhere. When you set // this, each time you append or push a list item, zlist will take a copy // of the string value. Then, when you destroy the list, it will free all // item values automatically. If you use any other technique to allocate // list values, you must free them explicitly before destroying the list. // The usual technique is to pop list items and destroy them, until the // list is empty. CZMQ_EXPORT void zlist_autofree (zlist_t *self); // Sets a compare function for this list. The function compares two items. // It returns an integer less than, equal to, or greater than zero if the // first item is found, respectively, to be less than, to match, or be // greater than the second item. // This function is used for sorting, removal and exists checking. CZMQ_EXPORT void zlist_comparefn (zlist_t *self, zlist_compare_fn fn); // Set a free function for the specified list item. When the item is // destroyed, the free function, if any, is called on that item. // Use this when list items are dynamically allocated, to ensure that // you don't have memory leaks. You can pass 'free' or NULL as a free_fn. // Returns the item, or NULL if there is no such item. CZMQ_EXPORT void * zlist_freefn (zlist_t *self, void *item, zlist_free_fn fn, bool at_tail); #ifdef CZMQ_BUILD_EXTRA // Self test of this class. CZMQ_EXPORT void zlist_test (bool verbose); #endif // CZMQ_BUILD_EXTRA // @end #ifdef __cplusplus } #endif #endif powerman-2.4.4/src/libczmq/zlistx.c000066400000000000000000000633321467035776500173350ustar00rootroot00000000000000/* ========================================================================= zlistx - extended generic list container Copyright (c) the Contributors as noted in the AUTHORS file. This file is part of CZMQ, the high-level C binding for 0MQ: http://czmq.zeromq.org. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. ========================================================================= */ /* @header Provides a generic doubly-linked list container. This container provides hooks for duplicator, comparator, and destructor functions. These tie into CZMQ and standard C semantics, so e.g. for string items you can use strdup, strcmp, and zstr_free. To store custom objects, define your own duplicator and comparator, and use the standard object destructor. @discuss This is a reworking of the simpler zlist container. It is faster to insert and delete items anywhere in the list, and to keep ordered lists. @end */ #include "czmq.h" #include "czmq_internal.h" #define NODE_TAG 0xcafe0006 // List node, used internally only typedef struct _node_t { uint32_t tag; // Object tag for validity checking struct _node_t *next; struct _node_t *prev; void *item; } node_t; // --------------------------------------------------------------------- // Structure of our class struct _zlistx_t { node_t *head; // First item in list, if any node_t *cursor; // Current cursors for iteration size_t size; // Number of items in list // Function callbacks for duplicating and destroying items, if any zlistx_duplicator_fn *duplicator; zlistx_destructor_fn *destructor; zlistx_comparator_fn *comparator; }; // Initialize a list node and attach to the prev and next nodes, or itself // if these are specified as null. Returns new node. static node_t * s_node_new (void *item) { node_t *self = (node_t *) zmalloc (sizeof (node_t)); assert (self); self->tag = NODE_TAG; self->prev = self; self->next = self; self->item = item; return self; } // Removing and inserting a node are actually the same operation: // swap (node->next, prev->next) // swap (node->prev, next->prev) // Which require only that the node be initialized to point to itself. // When inserting, node goes in between prev and next. static void s_node_relink (node_t *node, node_t *prev, node_t *next) { node_t *temp = node->next; node->next = prev->next; prev->next = temp; temp = node->prev; node->prev = next->prev; next->prev = temp; } // Default comparator static int s_comparator (const void *item1, const void *item2) { if (item1 == item2) return 0; else if (item1 < item2) return -1; else return 1; } // -------------------------------------------------------------------------- // Create a new, empty list. zlistx_t * zlistx_new (void) { zlistx_t *self = (zlistx_t *) zmalloc (sizeof (zlistx_t)); assert (self); self->head = s_node_new (NULL); assert (self->head); self->cursor = self->head; self->comparator = s_comparator; return self; } // -------------------------------------------------------------------------- // Destroy a list. If an item destructor was specified, all items in the // list are automatically destroyed as well. void zlistx_destroy (zlistx_t **self_p) { assert (self_p); if (*self_p) { zlistx_t *self = *self_p; zlistx_purge (self); freen (self->head); freen (self); *self_p = NULL; } } // -------------------------------------------------------------------------- // Add an item to the head of the list. Calls the item duplicator, if any, // on the item. Resets cursor to list head. Returns an item handle on // success. void * zlistx_add_start (zlistx_t *self, void *item) { assert (self); assert (item); if (self->duplicator) { item = (self->duplicator) (item); assert (item); } node_t *node = s_node_new (item); assert (node); // Insert after head s_node_relink (node, self->head, self->head->next); self->cursor = self->head; self->size++; return node; } // -------------------------------------------------------------------------- // Add an item to the tail of the list. Calls the item duplicator, if any, // on the item. Resets cursor to list head. Returns an item handle on // success. void * zlistx_add_end (zlistx_t *self, void *item) { assert (self); assert (item); if (self->duplicator) { item = (self->duplicator) (item); assert (item); } node_t *node = s_node_new (item); assert (node); // Insert before head s_node_relink (node, self->head->prev, self->head); self->cursor = self->head; self->size++; return node; } // -------------------------------------------------------------------------- // Return the number of items in the list size_t zlistx_size (zlistx_t *self) { assert (self); return self->size; } // -------------------------------------------------------------------------- // Return the item at the head of list. If the list is empty, returns NULL. // Leaves cursor as-is. void * zlistx_head (zlistx_t *self) { assert (self); return self->head? self->head->next->item: NULL; } // -------------------------------------------------------------------------- // Return the item at the tail of list. If the list is empty, returns NULL. // Leaves cursor as-is. void * zlistx_tail (zlistx_t *self) { assert (self); return self->head? self->head->prev->item: NULL; } // -------------------------------------------------------------------------- // Return the item at the head of list. If the list is empty, returns NULL. // Leaves cursor pointing at the head item, or NULL if the list is empty. void * zlistx_first (zlistx_t *self) { assert (self); self->cursor = self->head->next; return self->cursor == self->head? NULL: self->cursor->item; } // -------------------------------------------------------------------------- // Return the next item. At the end of the list (or in an empty list), // returns NULL. Use repeated zlistx_next () calls to work through the list // from zlistx_first (). First time, acts as zlistx_first(). void * zlistx_next (zlistx_t *self) { assert (self); self->cursor = self->cursor->next; return self->cursor == self->head? NULL: self->cursor->item; } // -------------------------------------------------------------------------- // Return the previous item. At the start of the list (or in an empty list), // returns NULL. Use repeated zlistx_prev () calls to work through the list // backwards from zlistx_last (). First time, acts as zlistx_last(). void * zlistx_prev (zlistx_t *self) { assert (self); self->cursor = self->cursor->prev; return self->cursor == self->head? NULL: self->cursor->item; } // -------------------------------------------------------------------------- // Return the item at the tail of list. If the list is empty, returns NULL. // Leaves cursor pointing at the tail item, or NULL if the list is empty. void * zlistx_last (zlistx_t *self) { assert (self); self->cursor = self->head->prev; return self->cursor == self->head? NULL: self->cursor->item; } // -------------------------------------------------------------------------- // Returns the value of the item at the cursor, or NULL if the cursor is // not pointing to an item. void * zlistx_item (zlistx_t *self) { assert (self); return self->cursor == self->head? NULL: self->cursor->item; } // -------------------------------------------------------------------------- // Returns the handle of the item at the cursor, or NULL if the cursor is // not pointing to an item. void * zlistx_cursor (zlistx_t *self) { assert (self); return self->cursor == self->head? NULL: self->cursor; } // -------------------------------------------------------------------------- // Returns the item associated with the given list handle, or NULL if passed // handle is NULL. asserts that the passed in ptr points to a list node. void * zlistx_handle_item (void *handle) { if (!handle) return NULL; node_t *node = (node_t *) handle; assert (node->tag == NODE_TAG); return node->item; } // -------------------------------------------------------------------------- // Find an item in the list, searching from the start. Uses the item // comparator, if any, else compares item values directly. Returns the // item handle found, or NULL. Sets the cursor to the found item, if any. void * zlistx_find (zlistx_t *self, void *item) { assert (self); assert (item); // Scan list for item, this is a O(N) operation node_t *node = self->head->next; while (node != self->head) { if (self->comparator (node->item, item) == 0) { self->cursor = node; return node; } node = node->next; } return NULL; } // -------------------------------------------------------------------------- // Detach an item from the list, using its handle. The item is not modified, // and the caller is responsible for destroying it if necessary. If handle is // null, detaches the first item on the list. Returns item that was detached, // or null if none was. If cursor was at item, moves cursor to previous item, // so you can detach items while iterating forwards through a list. void * zlistx_detach (zlistx_t *self, void *handle) { assert (self); node_t *node = (node_t *) handle; if (!node) node = self->head->next == self->head? NULL: self->head->next; // Now detach node from list, without destroying item if (node) { // Reposition cursor so that delete/detach works during iteration if (self->cursor == node) self->cursor = self->cursor->prev; // Remove node from list assert (node->tag == NODE_TAG); s_node_relink (node, node->prev, node->next); node->tag = 0xDeadBeef; void *item = node->item; freen (node); self->size--; return item; } else { assert (self->size == 0); return NULL; } } // -------------------------------------------------------------------------- // Detach item at the cursor, if any, from the list. The item is not modified, // and the caller is responsible for destroying it as necessary. Returns item // that was detached, or null if none was. Moves cursor to previous item, so // you can detach items while iterating forwards through a list. void * zlistx_detach_cur (zlistx_t *self) { return zlistx_detach (self, zlistx_cursor (self)); } // -------------------------------------------------------------------------- // Delete an item, using its handle. Calls the item destructor if any is // set. If handle is null, deletes the first item on the list. Returns 0 // if an item was deleted, -1 if not. If cursor was at item, moves cursor // to previous item, so you can delete items while iterating forwards // through a list. int zlistx_delete (zlistx_t *self, void *handle) { assert (self); void *item = zlistx_detach (self, handle); if (item) { if (self->destructor) self->destructor (&item); return 0; } else return -1; } // -------------------------------------------------------------------------- // Move an item to the start of the list, via its handle. void zlistx_move_start (zlistx_t *self, void *handle) { assert (self); assert (handle); node_t *node = (node_t *) handle; assert (node->tag == NODE_TAG); node_t *next = self->head->next; if (node != next) { // Remove node from list, insert before next node s_node_relink (node, node->prev, node->next); s_node_relink (node, next->prev, next); } } // -------------------------------------------------------------------------- // Move an item to the end of the list, via its handle. void zlistx_move_end (zlistx_t *self, void *handle) { assert (self); assert (handle); node_t *node = (node_t *) handle; assert (node->tag == NODE_TAG); node_t *prev = self->head->prev; if (node != prev) { // Remove node from list, insert after prev node s_node_relink (node, node->prev, node->next); s_node_relink (node, prev, prev->next); } } // -------------------------------------------------------------------------- // Remove all items from the list, and destroy them if the item destructor // is set. void zlistx_purge (zlistx_t *self) { assert (self); while (zlistx_size (self) > 0) zlistx_delete (self, NULL); } // -------------------------------------------------------------------------- // Sort the list. If an item comparator was set, calls that to compare // items, otherwise compares on item value. The sort is not stable, so may // reorder equal items. void zlistx_sort (zlistx_t *self) { // Uses a comb sort, which is simple and reasonably fast // See http://en.wikipedia.org/wiki/Comb_sort assert (self); size_t gap = self->size; bool swapped = false; while (gap > 1 || swapped) { gap = (size_t) ((double) gap / 1.3); node_t *base = self->head->next; node_t *test = self->head->next; size_t jump = gap; while (jump--) test = test->next; swapped = false; while (base != self->head && test != self->head) { if (self->comparator (base->item, test->item) > 0) { // We don't actually swap nodes, just the items in the nodes. // This is ridiculously simple and confuses the heck out of // me every time I re-read the code, as I expect to see the // nodes being swapped. Hence this comment. -- PH 2014/09/06 void *item = base->item; base->item = test->item; test->item = item; swapped = true; } base = base->next; test = test->next; } } } // -------------------------------------------------------------------------- // Create a new node and insert it into a sorted list. Calls the item // duplicator, if any, on the item. If low_value is true, starts searching // from the start of the list, otherwise searches from the end. Use the item // comparator, if any, to find where to place the new node. Returns a handle // to the new node, or NULL if memory was exhausted. Resets the cursor to the // list head. void * zlistx_insert (zlistx_t *self, void *item, bool low_value) { assert (self); if (self->duplicator) { item = (self->duplicator) (item); assert (item); } node_t *node = s_node_new (item); assert (node); zlistx_reorder (self, node, low_value); self->cursor = self->head; self->size++; return node; } // -------------------------------------------------------------------------- // Move an item, specified by handle, into position in a sorted list. Uses // the item comparator, if any, to determine the new location. If low_value // is true, starts searching from the start of the list, otherwise searches // from the end. void zlistx_reorder (zlistx_t *self, void *handle, bool low_value) { assert (self); assert (handle); node_t *node = (node_t *) handle; assert (node->tag == NODE_TAG); // Remove node from list, if it's attached s_node_relink (node, node->prev, node->next); if (low_value) { node_t *next = self->head->next; while (next != self->head) { if (self->comparator (node->item, next->item) <= 0) break; next = next->next; } // Relink node before next node s_node_relink (node, next->prev, next); } else { node_t *prev = self->head->prev; while (prev != self->head) { if (self->comparator (prev->item, node->item) <= 0) break; prev = prev->prev; } // Relink node after prev node s_node_relink (node, prev, prev->next); } } // -------------------------------------------------------------------------- // Make a copy of the list; items are duplicated if you set a duplicator // for the list, otherwise not. Copying a null reference returns a null // reference. zlistx_t * zlistx_dup (zlistx_t *self) { if (!self) return NULL; zlistx_t *copy = zlistx_new (); if (copy) { // Copy item handlers copy->destructor = self->destructor; copy->duplicator = self->duplicator; copy->comparator = self->comparator; // Copy nodes node_t *node; for (node = self->head->next; node != self->head; node = node->next) zlistx_add_end (copy, node->item); } return copy; } // -------------------------------------------------------------------------- // Set a user-defined deallocator for list items; by default items are not // freed when the list is destroyed. void zlistx_set_destructor (zlistx_t *self, zlistx_destructor_fn destructor) { assert (self); self->destructor = destructor; } // -------------------------------------------------------------------------- // Set a user-defined duplicator for list items; by default items are not // copied when the list is duplicated. void zlistx_set_duplicator (zlistx_t *self, zlistx_duplicator_fn duplicator) { assert (self); self->duplicator = duplicator; } // -------------------------------------------------------------------------- // Set a user-defined comparator for zlistx_find and zlistx_sort; the method // must return -1, 0, or 1 depending on whether item1 is less than, equal to, // or greater than, item2. void zlistx_set_comparator (zlistx_t *self, zlistx_comparator_fn comparator) { assert (self); self->comparator = comparator; } #ifdef CZMQ_BUILD_EXTRA // -------------------------------------------------------------------------- // Serialize list to a binary frame that can be sent in a message. // The packed format is compatible with the 'strings' type implemented by zproto: // // ; A list of strings // list = list-count *longstr // list-count = number-4 // // ; Strings are always length + text contents // longstr = number-4 *VCHAR // // ; Numbers are unsigned integers in network byte order // number-4 = 4OCTET // Caller owns return value and must destroy it when done. zframe_t * zlistx_pack (zlistx_t *self) { assert (self); // First, calculate the packed data size size_t frame_size = 4; // List size, number-4 char* item = (char *) zlistx_first (self); while (item) { frame_size += 4 + strlen (item); item = (char *) zlistx_next (self); } // Now serialize items into the frame zframe_t *frame = zframe_new (NULL, frame_size); if (!frame) return NULL; byte *needle = zframe_data (frame); *(uint32_t *) needle = htonl ((u_long) self->size); needle += 4; item = (char *) zlistx_first (self); while (item) { size_t length = strlen (item); uint32_t serialize = htonl ((u_long) length); memcpy (needle, &serialize, 4); needle += 4; memcpy (needle, item, length); needle += length; item = (char *) zlistx_next (self); } return frame; } // -------------------------------------------------------------------------- // Unpack binary frame into a new list. Packed data must follow format // defined by zlistx_pack. List is set to autofree. An empty frame // unpacks to an empty list. zlistx_t * zlistx_unpack (zframe_t *frame) { zlistx_t *self = zlistx_new (); if (!self) return NULL; // List will free values in destructor zlistx_set_destructor (self, (zlistx_destructor_fn *) zstr_free); assert (frame); if (zframe_size (frame) < 4) return self; byte *needle = zframe_data (frame); byte *ceiling = needle + zframe_size (frame); size_t nbr_items = ntohl (*(uint32_t *) needle); needle +=4; while (nbr_items && needle < ceiling) { if (needle + 4 <= ceiling) { size_t length = ntohl (*(uint32_t *)needle); needle += 4; // Be wary of malformed frames if (needle + length <= ceiling) { char * item = (char *) zmalloc (length + 1); assert (item); memcpy (item, needle, length); item[length] = 0; needle += length; if (!zlistx_add_end (self, item)) { zlistx_destroy (&self); break; } } else { zlistx_destroy (&self); break; } } else { zlistx_destroy (&self); break; } } if (self) zlistx_set_duplicator (self, (zlistx_duplicator_fn *) strdup); return self; } // -------------------------------------------------------------------------- // Runs selftest of class void zlistx_test (bool verbose) { printf (" * zlistx: "); // @selftest zlistx_t *list = zlistx_new (); assert (list); assert (zlistx_size (list) == 0); // Test operations on an empty list assert (zlistx_head (list) == NULL); assert (zlistx_first (list) == NULL); assert (zlistx_last (list) == NULL); assert (zlistx_next (list) == NULL); assert (zlistx_prev (list) == NULL); assert (zlistx_find (list, "hello") == NULL); assert (zlistx_delete (list, NULL) == -1); assert (zlistx_detach (list, NULL) == NULL); assert (zlistx_delete (list, NULL) == -1); assert (zlistx_detach (list, NULL) == NULL); zlistx_purge (list); zlistx_sort (list); // Use item handlers zlistx_set_destructor (list, (zlistx_destructor_fn *) zstr_free); zlistx_set_duplicator (list, (zlistx_duplicator_fn *) strdup); zlistx_set_comparator (list, (zlistx_comparator_fn *) strcmp); // Try simple insert/sort/delete/next assert (zlistx_next (list) == NULL); zlistx_add_end (list, "world"); assert (streq ((char *) zlistx_next (list), "world")); assert (streq ((char *) zlistx_head (list), "world")); zlistx_add_end (list, "hello"); assert (streq ((char *) zlistx_prev (list), "hello")); zlistx_sort (list); assert (zlistx_size (list) == 2); void *handle = zlistx_find (list, "hello"); char *item1 = (char *) zlistx_item (list); char *item2 = (char *) zlistx_handle_item (handle); assert (item1 == item2); assert (streq (item1, "hello")); zlistx_delete (list, handle); assert (zlistx_size (list) == 1); char *string = (char *) zlistx_detach (list, NULL); assert (streq (string, "world")); freen (string); assert (zlistx_size (list) == 0); // Check next/back work // Now populate the list with items zlistx_add_start (list, "five"); zlistx_add_end (list, "six"); zlistx_add_start (list, "four"); zlistx_add_end (list, "seven"); zlistx_add_start (list, "three"); zlistx_add_end (list, "eight"); zlistx_add_start (list, "two"); zlistx_add_end (list, "nine"); zlistx_add_start (list, "one"); zlistx_add_end (list, "ten"); // Test our navigation skills assert (zlistx_size (list) == 10); assert (streq ((char *) zlistx_last (list), "ten")); assert (streq ((char *) zlistx_prev (list), "nine")); assert (streq ((char *) zlistx_prev (list), "eight")); assert (streq ((char *) zlistx_prev (list), "seven")); assert (streq ((char *) zlistx_prev (list), "six")); assert (streq ((char *) zlistx_prev (list), "five")); assert (streq ((char *) zlistx_first (list), "one")); assert (streq ((char *) zlistx_next (list), "two")); assert (streq ((char *) zlistx_next (list), "three")); assert (streq ((char *) zlistx_next (list), "four")); // Sort by alphabetical order zlistx_sort (list); assert (streq ((char *) zlistx_first (list), "eight")); assert (streq ((char *) zlistx_last (list), "two")); // Moving items around handle = zlistx_find (list, "six"); zlistx_move_start (list, handle); assert (streq ((char *) zlistx_first (list), "six")); zlistx_move_end (list, handle); assert (streq ((char *) zlistx_last (list), "six")); zlistx_sort (list); assert (streq ((char *) zlistx_last (list), "two")); // Copying a list zlistx_t *copy = zlistx_dup (list); assert (copy); assert (zlistx_size (copy) == 10); assert (streq ((char *) zlistx_first (copy), "eight")); assert (streq ((char *) zlistx_last (copy), "two")); zlistx_destroy (©); // Delete items while iterating string = (char *) zlistx_first (list); assert (streq (string, "eight")); string = (char *) zlistx_next (list); assert (streq (string, "five")); zlistx_delete (list, zlistx_cursor (list)); string = (char *) zlistx_next (list); assert (streq (string, "four")); // Test pack/unpack methods zframe_t *frame = zlistx_pack (list); copy = zlistx_unpack (frame); assert (copy); zframe_destroy (&frame); assert (zlistx_size (copy) == zlistx_size (list)); char *item_orig = (char *) zlistx_first (list); char *item_copy = (char *) zlistx_first (copy); while (item_orig) { assert (strcmp(item_orig, item_copy) == 0); item_orig = (char *) zlistx_next (list); item_copy = (char *) zlistx_next (copy); } zlistx_destroy (©); zlistx_purge (list); zlistx_destroy (&list); #if defined (__WINDOWS__) zsys_shutdown(); #endif // @end printf ("OK\n"); } #endif // CZMQ_BUILD_EXTRA powerman-2.4.4/src/libczmq/zlistx.h000066400000000000000000000214301467035776500173330ustar00rootroot00000000000000/* ========================================================================= zlistx - extended generic list container Copyright (c) the Contributors as noted in the AUTHORS file. This file is part of CZMQ, the high-level C binding for 0MQ: http://czmq.zeromq.org. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. ========================================================================= */ #ifndef __FLUXZLISTX_H_INCLUDED__ #define __FLUXZLISTX_H_INCLUDED__ #ifdef __cplusplus extern "C" { #endif // @warning THE FOLLOWING @INTERFACE BLOCK IS AUTO-GENERATED BY ZPROJECT // @warning Please edit the model at "api/zlistx.api" to make changes. // @interface // This is a stable class, and may not change except for emergencies. It // is provided in stable builds. // This class has draft methods, which may change over time. They are not // in stable releases, by default. Use --enable-drafts to enable. // Destroy an item typedef void (zlistx_destructor_fn) ( void **item); // Duplicate an item typedef void * (zlistx_duplicator_fn) ( const void *item); // Compare two items, for sorting typedef int (zlistx_comparator_fn) ( const void *item1, const void *item2); // Create a new, empty list. CZMQ_EXPORT zlistx_t * zlistx_new (void); // Destroy a list. If an item destructor was specified, all items in the // list are automatically destroyed as well. CZMQ_EXPORT void zlistx_destroy (zlistx_t **self_p); // Add an item to the head of the list. Calls the item duplicator, if any, // on the item. Resets cursor to list head. Returns an item handle on // success, NULL if memory was exhausted. CZMQ_EXPORT void * zlistx_add_start (zlistx_t *self, void *item); // Add an item to the tail of the list. Calls the item duplicator, if any, // on the item. Resets cursor to list head. Returns an item handle on // success, NULL if memory was exhausted. CZMQ_EXPORT void * zlistx_add_end (zlistx_t *self, void *item); // Return the number of items in the list CZMQ_EXPORT size_t zlistx_size (zlistx_t *self); // Return first item in the list, or null, leaves the cursor CZMQ_EXPORT void * zlistx_head (zlistx_t *self); // Return last item in the list, or null, leaves the cursor CZMQ_EXPORT void * zlistx_tail (zlistx_t *self); // Return the item at the head of list. If the list is empty, returns NULL. // Leaves cursor pointing at the head item, or NULL if the list is empty. CZMQ_EXPORT void * zlistx_first (zlistx_t *self); // Return the next item. At the end of the list (or in an empty list), // returns NULL. Use repeated zlistx_next () calls to work through the list // from zlistx_first (). First time, acts as zlistx_first(). CZMQ_EXPORT void * zlistx_next (zlistx_t *self); // Return the previous item. At the start of the list (or in an empty list), // returns NULL. Use repeated zlistx_prev () calls to work through the list // backwards from zlistx_last (). First time, acts as zlistx_last(). CZMQ_EXPORT void * zlistx_prev (zlistx_t *self); // Return the item at the tail of list. If the list is empty, returns NULL. // Leaves cursor pointing at the tail item, or NULL if the list is empty. CZMQ_EXPORT void * zlistx_last (zlistx_t *self); // Returns the value of the item at the cursor, or NULL if the cursor is // not pointing to an item. CZMQ_EXPORT void * zlistx_item (zlistx_t *self); // Returns the handle of the item at the cursor, or NULL if the cursor is // not pointing to an item. CZMQ_EXPORT void * zlistx_cursor (zlistx_t *self); // Returns the item associated with the given list handle, or NULL if passed // in handle is NULL. Asserts that the passed in handle points to a list element. CZMQ_EXPORT void * zlistx_handle_item (void *handle); // Find an item in the list, searching from the start. Uses the item // comparator, if any, else compares item values directly. Returns the // item handle found, or NULL. Sets the cursor to the found item, if any. CZMQ_EXPORT void * zlistx_find (zlistx_t *self, void *item); // Detach an item from the list, using its handle. The item is not modified, // and the caller is responsible for destroying it if necessary. If handle is // null, detaches the first item on the list. Returns item that was detached, // or null if none was. If cursor was at item, moves cursor to previous item, // so you can detach items while iterating forwards through a list. CZMQ_EXPORT void * zlistx_detach (zlistx_t *self, void *handle); // Detach item at the cursor, if any, from the list. The item is not modified, // and the caller is responsible for destroying it as necessary. Returns item // that was detached, or null if none was. Moves cursor to previous item, so // you can detach items while iterating forwards through a list. CZMQ_EXPORT void * zlistx_detach_cur (zlistx_t *self); // Delete an item, using its handle. Calls the item destructor if any is // set. If handle is null, deletes the first item on the list. Returns 0 // if an item was deleted, -1 if not. If cursor was at item, moves cursor // to previous item, so you can delete items while iterating forwards // through a list. CZMQ_EXPORT int zlistx_delete (zlistx_t *self, void *handle); // Move an item to the start of the list, via its handle. CZMQ_EXPORT void zlistx_move_start (zlistx_t *self, void *handle); // Move an item to the end of the list, via its handle. CZMQ_EXPORT void zlistx_move_end (zlistx_t *self, void *handle); // Remove all items from the list, and destroy them if the item destructor // is set. CZMQ_EXPORT void zlistx_purge (zlistx_t *self); // Sort the list. If an item comparator was set, calls that to compare // items, otherwise compares on item value. The sort is not stable, so may // reorder equal items. CZMQ_EXPORT void zlistx_sort (zlistx_t *self); // Create a new node and insert it into a sorted list. Calls the item // duplicator, if any, on the item. If low_value is true, starts searching // from the start of the list, otherwise searches from the end. Use the item // comparator, if any, to find where to place the new node. Returns a handle // to the new node, or NULL if memory was exhausted. Resets the cursor to the // list head. CZMQ_EXPORT void * zlistx_insert (zlistx_t *self, void *item, bool low_value); // Move an item, specified by handle, into position in a sorted list. Uses // the item comparator, if any, to determine the new location. If low_value // is true, starts searching from the start of the list, otherwise searches // from the end. CZMQ_EXPORT void zlistx_reorder (zlistx_t *self, void *handle, bool low_value); // Make a copy of the list; items are duplicated if you set a duplicator // for the list, otherwise not. Copying a null reference returns a null // reference. CZMQ_EXPORT zlistx_t * zlistx_dup (zlistx_t *self); // Set a user-defined deallocator for list items; by default items are not // freed when the list is destroyed. CZMQ_EXPORT void zlistx_set_destructor (zlistx_t *self, zlistx_destructor_fn destructor); // Set a user-defined duplicator for list items; by default items are not // copied when the list is duplicated. CZMQ_EXPORT void zlistx_set_duplicator (zlistx_t *self, zlistx_duplicator_fn duplicator); // Set a user-defined comparator for zlistx_find and zlistx_sort; the method // must return -1, 0, or 1 depending on whether item1 is less than, equal to, // or greater than, item2. CZMQ_EXPORT void zlistx_set_comparator (zlistx_t *self, zlistx_comparator_fn comparator); #ifdef CZMQ_BUILD_EXTRA // Self test of this class. CZMQ_EXPORT void zlistx_test (bool verbose); #ifdef CZMQ_BUILD_DRAFT_API // *** Draft method, for development use, may change without warning *** // Unpack binary frame into a new list. Packed data must follow format // defined by zlistx_pack. List is set to autofree. An empty frame // unpacks to an empty list. CZMQ_EXPORT zlistx_t * zlistx_unpack (zframe_t *frame); // *** Draft method, for development use, may change without warning *** // Serialize list to a binary frame that can be sent in a message. // The packed format is compatible with the 'strings' type implemented by zproto: // // ; A list of strings // list = list-count *longstr // list-count = number-4 // // ; Strings are always length + text contents // longstr = number-4 *VCHAR // // ; Numbers are unsigned integers in network byte order // number-4 = 4OCTET // Caller owns return value and must destroy it when done. CZMQ_EXPORT zframe_t * zlistx_pack (zlistx_t *self); #endif // CZMQ_BUILD_DRAFT_API #endif // CZMQ_BUILD_EXTRA // @end #ifdef __cplusplus } #endif #endif powerman-2.4.4/src/liblsd/000077500000000000000000000000001467035776500154355ustar00rootroot00000000000000powerman-2.4.4/src/liblsd/Makefile.am000066400000000000000000000003521467035776500174710ustar00rootroot00000000000000AM_CFLAGS = \ @WARNING_CFLAGS@ \ -Wno-parentheses \ -Wno-error=parentheses AM_CPPFLAGS = noinst_LTLIBRARIES = liblsd.la liblsd_la_SOURCES = \ hostlist.c \ hostlist.h \ list.c \ list.h \ hash.c \ hash.h \ cbuf.c \ cbuf.h powerman-2.4.4/src/liblsd/cbuf.c000066400000000000000000001366241467035776500165340ustar00rootroot00000000000000/***************************************************************************** * Copyright (C) 2002-2005 The Regents of the University of California. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). * Written by Chris Dunlap . * * This file is from LSD-Tools, the LLNL Software Development Toolbox. * * LSD-Tools 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. * * LSD-Tools is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with LSD-Tools; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***************************************************************************** * Refer to "cbuf.h" for documentation on public functions. *****************************************************************************/ #ifdef HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #ifdef WITH_PTHREADS # include #endif /* WITH_PTHREADS */ #include #include #include #include #include #include "cbuf.h" /***************************************************************************** * lsd_fatal_error *****************************************************************************/ #ifdef WITH_LSD_FATAL_ERROR_FUNC # undef lsd_fatal_error extern void lsd_fatal_error (char *file, int line, char *mesg); #else /* !WITH_LSD_FATAL_ERROR_FUNC */ # ifndef lsd_fatal_error # include # include # include # define lsd_fatal_error(file, line, mesg) \ do { \ fprintf (stderr, "ERROR: [%s:%d] %s: %s\n", \ file, line, mesg, strerror (errno)); \ } while (0) # endif /* !lsd_fatal_error */ #endif /* !WITH_LSD_FATAL_ERROR_FUNC */ /***************************************************************************** * lsd_nomem_error *****************************************************************************/ #ifdef WITH_LSD_NOMEM_ERROR_FUNC # undef lsd_nomem_error extern void * lsd_nomem_error (char *file, int line, char *mesg); #else /* !WITH_LSD_NOMEM_ERROR_FUNC */ # ifndef lsd_nomem_error # define lsd_nomem_error(file, line, mesg) (NULL) # endif /* !lsd_nomem_error */ #endif /* !WITH_LSD_NOMEM_ERROR_FUNC */ /***************************************************************************** * Constants *****************************************************************************/ #define CBUF_CHUNK 1000 #define CBUF_MAGIC 0xDEADBEEF #define CBUF_MAGIC_LEN (sizeof (unsigned long)) /***************************************************************************** * Data Types *****************************************************************************/ struct cbuf { #ifndef NDEBUG unsigned long magic; /* cookie for asserting validity */ #endif /* !NDEBUG */ #ifdef WITH_PTHREADS pthread_mutex_t mutex; /* mutex to protect access to cbuf */ #endif /* WITH_PTHREADS */ int alloc; /* num bytes malloc'd/realloc'd */ int minsize; /* min bytes of data to allocate */ int maxsize; /* max bytes of data to allocate */ int size; /* num bytes of data allocated */ int used; /* num bytes of unread data */ cbuf_overwrite_t overwrite; /* overwrite option behavior */ int got_wrap; /* true if data has wrapped */ int i_in; /* index to where data is written in */ int i_out; /* index to where data is read out */ int i_rep; /* index to where data is replayable */ unsigned char *data; /* ptr to circular buffer of data */ }; typedef int (*cbuf_iof) (void *cbuf_data, void *arg, int len); /***************************************************************************** * Prototypes *****************************************************************************/ static int cbuf_find_replay_line (cbuf_t cb, int chars, int *nlines, int *nl); static int cbuf_find_unread_line (cbuf_t cb, int chars, int *nlines); static int cbuf_get_fd (void *dstbuf, int *psrcfd, int len); static int cbuf_get_mem (void *dstbuf, unsigned char **psrcbuf, int len); static int cbuf_put_fd (void *srcbuf, int *pdstfd, int len); static int cbuf_put_mem (void *srcbuf, unsigned char **pdstbuf, int len); static int cbuf_copier (cbuf_t src, cbuf_t dst, int len, int *ndropped); static int cbuf_dropper (cbuf_t cb, int len); static int cbuf_reader (cbuf_t src, int len, cbuf_iof putf, void *dst); static int cbuf_replayer (cbuf_t src, int len, cbuf_iof putf, void *dst); static int cbuf_writer (cbuf_t dst, int len, cbuf_iof getf, void *src, int *ndropped); static int cbuf_grow (cbuf_t cb, int n); static int cbuf_shrink (cbuf_t cb); #ifndef NDEBUG static int cbuf_is_valid (cbuf_t cb); #endif /* !NDEBUG */ /***************************************************************************** * Macros *****************************************************************************/ #ifndef MAX # define MAX(x,y) (((x) >= (y)) ? (x) : (y)) #endif /* !MAX */ #ifndef MIN # define MIN(x,y) (((x) <= (y)) ? (x) : (y)) #endif /* !MIN */ #ifdef WITH_PTHREADS # define cbuf_mutex_init(cb) \ do { \ int e = pthread_mutex_init (&cb->mutex, NULL); \ if (e) { \ errno = e; \ lsd_fatal_error (__FILE__, __LINE__, "cbuf mutex init"); \ abort (); \ } \ } while (0) # define cbuf_mutex_lock(cb) \ do { \ int e = pthread_mutex_lock (&cb->mutex); \ if (e) { \ errno = e; \ lsd_fatal_error (__FILE__, __LINE__, "cbuf mutex lock"); \ abort (); \ } \ } while (0) # define cbuf_mutex_unlock(cb) \ do { \ int e = pthread_mutex_unlock (&cb->mutex); \ if (e) { \ errno = e; \ lsd_fatal_error (__FILE__, __LINE__, "cbuf mutex unlock"); \ abort (); \ } \ } while (0) # define cbuf_mutex_destroy(cb) \ do { \ int e = pthread_mutex_destroy (&cb->mutex); \ if (e) { \ errno = e; \ lsd_fatal_error (__FILE__, __LINE__, "cbuf mutex destroy"); \ abort (); \ } \ } while (0) # ifndef NDEBUG static int cbuf_mutex_is_locked (cbuf_t cb); # endif /* !NDEBUG */ #else /* !WITH_PTHREADS */ # define cbuf_mutex_init(cb) # define cbuf_mutex_lock(cb) # define cbuf_mutex_unlock(cb) # define cbuf_mutex_destroy(cb) # define cbuf_mutex_is_locked(cb) (1) #endif /* !WITH_PTHREADS */ /***************************************************************************** * Functions *****************************************************************************/ cbuf_t cbuf_create (int minsize, int maxsize) { cbuf_t cb; if (minsize <= 0) { errno = EINVAL; return (NULL); } if (!(cb = malloc (sizeof (struct cbuf)))) { errno = ENOMEM; return (lsd_nomem_error (__FILE__, __LINE__, "cbuf struct")); } /* Circular buffer is empty when (i_in == i_out), * so reserve 1 byte for this sentinel. */ cb->alloc = minsize + 1; #ifndef NDEBUG /* Reserve space for the magic cookies used to protect the * cbuf data[] array from underflow and overflow. */ cb->alloc += 2 * CBUF_MAGIC_LEN; #endif /* !NDEBUG */ if (!(cb->data = malloc (cb->alloc))) { free (cb); errno = ENOMEM; return (lsd_nomem_error (__FILE__, __LINE__, "cbuf data")); } cbuf_mutex_init (cb); cb->minsize = minsize; cb->maxsize = (maxsize > minsize) ? maxsize : minsize; cb->size = minsize; cb->used = 0; cb->overwrite = CBUF_WRAP_MANY; cb->got_wrap = 0; cb->i_in = cb->i_out = cb->i_rep = 0; #ifndef NDEBUG /* C is for cookie, that's good enough for me, yeah! * The magic cookies are only defined during DEBUG code. * The first "magic" cookie is at the top of the structure. * Magic cookies are also placed at the top & bottom of the * cbuf data[] array to catch buffer underflow & overflow errors. */ cb->data += CBUF_MAGIC_LEN; /* jump forward past underflow magic */ cb->magic = CBUF_MAGIC; /* * Must use memcpy since overflow cookie may not be word-aligned. */ memcpy (cb->data - CBUF_MAGIC_LEN, (void *) &cb->magic, CBUF_MAGIC_LEN); memcpy (cb->data + cb->size + 1, (void *) &cb->magic, CBUF_MAGIC_LEN); cbuf_mutex_lock (cb); assert (cbuf_is_valid (cb)); cbuf_mutex_unlock (cb); #endif /* !NDEBUG */ return (cb); } void cbuf_destroy (cbuf_t cb) { assert (cb != NULL); cbuf_mutex_lock (cb); assert (cbuf_is_valid (cb)); #ifndef NDEBUG /* The moon sometimes looks like a C, but you can't eat that. * Munch the magic cookies before freeing memory. */ cb->magic = ~CBUF_MAGIC; /* the anti-cookie! */ memcpy (cb->data - CBUF_MAGIC_LEN, (void *) &cb->magic, CBUF_MAGIC_LEN); memcpy (cb->data + cb->size + 1, (void *) &cb->magic, CBUF_MAGIC_LEN); cb->data -= CBUF_MAGIC_LEN; /* jump back to what malloc returned */ #endif /* !NDEBUG */ free (cb->data); cbuf_mutex_unlock (cb); cbuf_mutex_destroy (cb); free (cb); return; } void cbuf_flush (cbuf_t cb) { assert (cb != NULL); cbuf_mutex_lock (cb); assert (cbuf_is_valid (cb)); /* * FIXME: Shrink buffer back to minimum size. */ cb->used = 0; cb->got_wrap = 0; cb->i_in = cb->i_out = cb->i_rep = 0; assert (cbuf_is_valid (cb)); cbuf_mutex_unlock (cb); return; } int cbuf_size (cbuf_t cb) { int size; assert (cb != NULL); cbuf_mutex_lock (cb); assert (cbuf_is_valid (cb)); size = cb->maxsize; cbuf_mutex_unlock (cb); return (size); } int cbuf_free (cbuf_t cb) { int nfree; assert (cb != NULL); cbuf_mutex_lock (cb); assert (cbuf_is_valid (cb)); nfree = cb->maxsize - cb->used; cbuf_mutex_unlock (cb); return (nfree); } int cbuf_used (cbuf_t cb) { int used; assert (cb != NULL); cbuf_mutex_lock (cb); assert (cbuf_is_valid (cb)); used = cb->used; cbuf_mutex_unlock (cb); return (used); } int cbuf_lines_used (cbuf_t cb) { int lines = -1; assert (cb != NULL); cbuf_mutex_lock (cb); assert (cbuf_is_valid (cb)); cbuf_find_unread_line (cb, cb->size, &lines); cbuf_mutex_unlock (cb); return (lines); } int cbuf_reused (cbuf_t cb) { /* If (O > R) * n = O - R * else * n = (O - 0) + ((S+1) - R). * (S+1) is used since data[] contains 'size' bytes + a 1-byte sentinel. */ int reused; assert (cb != NULL); cbuf_mutex_lock (cb); assert (cbuf_is_valid (cb)); reused = (cb->i_out - cb->i_rep + (cb->size + 1)) % (cb->size + 1); cbuf_mutex_unlock (cb); return (reused); } int cbuf_lines_reused (cbuf_t cb) { int lines = -1; assert (cb != NULL); cbuf_mutex_lock (cb); assert (cbuf_is_valid (cb)); cbuf_find_replay_line (cb, cb->size, &lines, NULL); cbuf_mutex_unlock (cb); return (lines); } int cbuf_is_empty (cbuf_t cb) { int used; assert (cb != NULL); cbuf_mutex_lock (cb); assert (cbuf_is_valid (cb)); used = cb->used; cbuf_mutex_unlock (cb); return (used == 0); } int cbuf_opt_get (cbuf_t cb, cbuf_opt_t name, int *value) { int rc = 0; assert (cb != NULL); if (value == NULL) { errno = EINVAL; return (-1); } cbuf_mutex_lock (cb); assert (cbuf_is_valid (cb)); if (name == CBUF_OPT_OVERWRITE) { *value = cb->overwrite; } else { errno = EINVAL; rc = -1; } cbuf_mutex_unlock (cb); return (rc); } int cbuf_opt_set (cbuf_t cb, cbuf_opt_t name, int value) { int rc = 0; assert (cb != NULL); cbuf_mutex_lock (cb); assert (cbuf_is_valid (cb)); if (name == CBUF_OPT_OVERWRITE) { if ( (value == CBUF_NO_DROP) || (value == CBUF_WRAP_ONCE) || (value == CBUF_WRAP_MANY) ) { cb->overwrite = value; } else { errno = EINVAL; rc = -1; } } else { errno = EINVAL; rc = -1; } assert (cbuf_is_valid (cb)); cbuf_mutex_unlock (cb); return (rc); } int cbuf_drop (cbuf_t src, int len) { assert (src != NULL); if (len < -1) { errno = EINVAL; return (-1); } if (len == 0) { return (0); } cbuf_mutex_lock (src); assert (cbuf_is_valid (src)); if (len == -1) { len = src->used; } else { len = MIN (len, src->used); } if (len > 0) { cbuf_dropper (src, len); } assert (cbuf_is_valid (src)); cbuf_mutex_unlock (src); return (len); } int cbuf_peek (cbuf_t src, void *dstbuf, int len) { int n; assert (src != NULL); if ((dstbuf == NULL) || (len < 0)) { errno = EINVAL; return (-1); } if (len == 0) { return (0); } cbuf_mutex_lock (src); assert (cbuf_is_valid (src)); n = cbuf_reader (src, len, (cbuf_iof) cbuf_put_mem, &dstbuf); assert (cbuf_is_valid (src)); cbuf_mutex_unlock (src); return (n); } int cbuf_read (cbuf_t src, void *dstbuf, int len) { int n; assert (src != NULL); if ((dstbuf == NULL) || (len < 0)) { errno = EINVAL; return (-1); } if (len == 0) { return (0); } cbuf_mutex_lock (src); assert (cbuf_is_valid (src)); n = cbuf_reader (src, len, (cbuf_iof) cbuf_put_mem, &dstbuf); if (n > 0) { cbuf_dropper (src, n); } assert (cbuf_is_valid (src)); cbuf_mutex_unlock (src); return (n); } int cbuf_replay (cbuf_t src, void *dstbuf, int len) { int n; assert (src != NULL); if ((dstbuf == NULL) || (len < 0)) { errno = EINVAL; return (-1); } if (len == 0) { return (0); } cbuf_mutex_lock (src); assert (cbuf_is_valid (src)); n = cbuf_replayer (src, len, (cbuf_iof) cbuf_put_mem, &dstbuf); assert (cbuf_is_valid (src)); cbuf_mutex_unlock (src); return (n); } int cbuf_rewind (cbuf_t src, int len) { int reused; assert (src != NULL); if (len < -1) { errno = EINVAL; return (-1); } if (len == 0) { return (0); } cbuf_mutex_lock (src); assert (cbuf_is_valid (src)); reused = (src->i_out - src->i_rep + (src->size + 1)) % (src->size + 1); if (len == -1) { len = reused; } else { len = MIN (len, reused); } if (len > 0) { src->used += len; src->i_out = (src->i_out - len + (src->size + 1)) % (src->size + 1); } assert (cbuf_is_valid (src)); cbuf_mutex_unlock (src); return (len); } int cbuf_write (cbuf_t dst, void *srcbuf, int len, int *ndropped) { int n; assert (dst != NULL); if (ndropped) { *ndropped = 0; } if ((srcbuf == NULL) || (len < 0)) { errno = EINVAL; return (-1); } if (len == 0) { return (0); } cbuf_mutex_lock (dst); assert (cbuf_is_valid (dst)); n = cbuf_writer (dst, len, (cbuf_iof) cbuf_get_mem, &srcbuf, ndropped); assert (cbuf_is_valid (dst)); cbuf_mutex_unlock (dst); return (n); } int cbuf_drop_line (cbuf_t src, int len, int lines) { int n; assert (src != NULL); if ((len < 0) || (lines < -1)) { errno = EINVAL; return (-1); } if (lines == 0) { return (0); } cbuf_mutex_lock (src); assert (cbuf_is_valid (src)); n = cbuf_find_unread_line (src, len, &lines); if (n > 0) { cbuf_dropper (src, n); } assert (cbuf_is_valid (src)); cbuf_mutex_unlock (src); return (n); } int cbuf_peek_line (cbuf_t src, char *dstbuf, int len, int lines) { int n, m, l; char *pdst; assert (src != NULL); if ((dstbuf == NULL) || (len < 0) || (lines < -1)) { errno = EINVAL; return (-1); } if (lines == 0) { return (0); } cbuf_mutex_lock (src); assert (cbuf_is_valid (src)); n = cbuf_find_unread_line (src, len - 1, &lines); if (n > 0) { if (len > 0) { m = MIN (n, len - 1); if (m > 0) { pdst = dstbuf; l = cbuf_reader (src, m, (cbuf_iof) cbuf_put_mem, &pdst); assert (l == m); } assert (m < len); dstbuf[m] = '\0'; } } assert (cbuf_is_valid (src)); cbuf_mutex_unlock (src); return (n); } int cbuf_read_line (cbuf_t src, char *dstbuf, int len, int lines) { int n, m, l; char *pdst; assert (src != NULL); if ((dstbuf == NULL) || (len < 0) || (lines < -1)) { errno = EINVAL; return (-1); } if (lines == 0) { return (0); } cbuf_mutex_lock (src); assert (cbuf_is_valid (src)); n = cbuf_find_unread_line (src, len - 1, &lines); if (n > 0) { if (len > 0) { m = MIN (n, len - 1); if (m > 0) { pdst = dstbuf; l = cbuf_reader (src, m, (cbuf_iof) cbuf_put_mem, &pdst); assert (l == m); } assert (m < len); dstbuf[m] = '\0'; } cbuf_dropper (src, n); } assert (cbuf_is_valid (src)); cbuf_mutex_unlock (src); return (n); } int cbuf_replay_line (cbuf_t src, char *dstbuf, int len, int lines) { int n, m, l; int nl; char *pdst; assert (src != NULL); if ((dstbuf == NULL) || (len < 0) || (lines < -1)) { errno = EINVAL; return (-1); } if (lines == 0) { return (0); } cbuf_mutex_lock (src); assert (cbuf_is_valid (src)); n = cbuf_find_replay_line (src, len - 1, &lines, &nl); if (n > 0) { if (len > 0) { assert ((nl == 0) || (nl == 1)); m = MIN (n, len - 1 - nl); m = MAX (m, 0); if (m > 0) { pdst = dstbuf; l = cbuf_replayer (src, m, (cbuf_iof) cbuf_put_mem, &pdst); assert (l == m); } /* Append newline if needed and space allows. */ if ((nl) && (len > 1)) { dstbuf[m++] = '\n'; } assert (m < len); dstbuf[m] = '\0'; n += nl; } } assert (cbuf_is_valid (src)); cbuf_mutex_unlock (src); return (n); } int cbuf_rewind_line (cbuf_t src, int len, int lines) { int n; assert (src != NULL); if ((len < 0) || (lines < -1)) { errno = EINVAL; return (-1); } if (lines == 0) { return (0); } cbuf_mutex_lock (src); assert (cbuf_is_valid (src)); n = cbuf_find_replay_line (src, len, &lines, NULL); if (n > 0) { src->used += n; src->i_out = (src->i_out - n + (src->size + 1)) % (src->size + 1); } assert (cbuf_is_valid (src)); cbuf_mutex_unlock (src); return (n); } int cbuf_write_line (cbuf_t dst, char *srcbuf, int *ndropped) { int len; int nfree, ncopy, n; int ndrop = 0, d; char *psrc = srcbuf; char *newline = "\n"; assert (dst != NULL); if (ndropped) { *ndropped = 0; } if (srcbuf == NULL) { errno = EINVAL; return (-1); } /* Compute number of bytes to effectively copy to dst cbuf. * Reserve space for the trailing newline if needed. */ len = ncopy = strlen (srcbuf); if ((len == 0) || (srcbuf[len - 1] != '\n')) { len++; } cbuf_mutex_lock (dst); assert (cbuf_is_valid (dst)); /* * Attempt to grow dst cbuf if necessary. */ nfree = dst->size - dst->used; if ((len > nfree) && (dst->size < dst->maxsize)) { nfree += cbuf_grow (dst, len - nfree); } /* Determine if src will fit (or be made to fit) in dst cbuf. */ if (dst->overwrite == CBUF_NO_DROP) { if (len > dst->size - dst->used) { errno = ENOSPC; len = -1; /* cannot return while mutex locked */ } } else if (dst->overwrite == CBUF_WRAP_ONCE) { if (len > dst->size) { errno = ENOSPC; len = -1; /* cannot return while mutex locked */ } } if (len > 0) { /* * Discard data that won't fit in dst cbuf. */ if (len > dst->size) { ndrop += len - dst->size; ncopy -= ndrop; psrc += ndrop; } /* Copy data from src string to dst cbuf. */ if (ncopy > 0) { n = cbuf_writer (dst, ncopy, (cbuf_iof) cbuf_get_mem, &psrc, &d); assert (n == ncopy); ndrop += d; } /* Append newline if needed. */ if (srcbuf[len - 1] != '\n') { n = cbuf_writer (dst, 1, (cbuf_iof) cbuf_get_mem, &newline, &d); assert (n == 1); ndrop += d; } } assert (cbuf_is_valid (dst)); cbuf_mutex_unlock (dst); if (ndropped) { *ndropped = ndrop; } return (len); } int cbuf_peek_to_fd (cbuf_t src, int dstfd, int len) { int n = 0; assert (src != NULL); if ((dstfd < 0) || (len < -1)) { errno = EINVAL; return (-1); } cbuf_mutex_lock (src); assert (cbuf_is_valid (src)); if (len == -1) { len = src->used; } if (len > 0) { n = cbuf_reader (src, len, (cbuf_iof) cbuf_put_fd, &dstfd); } assert (cbuf_is_valid (src)); cbuf_mutex_unlock (src); return (n); } int cbuf_read_to_fd (cbuf_t src, int dstfd, int len) { int n = 0; assert (src != NULL); if ((dstfd < 0) || (len < -1)) { errno = EINVAL; return (-1); } cbuf_mutex_lock (src); assert (cbuf_is_valid (src)); if (len == -1) { len = src->used; } if (len > 0) { n = cbuf_reader (src, len, (cbuf_iof) cbuf_put_fd, &dstfd); if (n > 0) { cbuf_dropper (src, n); } } assert (cbuf_is_valid (src)); cbuf_mutex_unlock (src); return (n); } int cbuf_replay_to_fd (cbuf_t src, int dstfd, int len) { int n = 0; assert (src != NULL); if ((dstfd < 0) || (len < -1)) { errno = EINVAL; return (-1); } cbuf_mutex_lock (src); assert (cbuf_is_valid (src)); if (len == -1) { len = src->size - src->used; } if (len > 0) { n = cbuf_replayer (src, len, (cbuf_iof) cbuf_put_fd, &dstfd); } assert (cbuf_is_valid (src)); cbuf_mutex_unlock (src); return (n); } int cbuf_write_from_fd (cbuf_t dst, int srcfd, int len, int *ndropped) { int n = 0; assert (dst != NULL); if (ndropped) { *ndropped = 0; } if ((srcfd < 0) || (len < -1)) { errno = EINVAL; return (-1); } cbuf_mutex_lock (dst); assert (cbuf_is_valid (dst)); if (len == -1) { /* * Try to use all of the free buffer space available for writing. * If it is all in use, try to grab another chunk. */ len = dst->size - dst->used; if (len == 0) { len = CBUF_CHUNK; } } if (len > 0) { n = cbuf_writer (dst, len, (cbuf_iof) cbuf_get_fd, &srcfd, ndropped); } assert (cbuf_is_valid (dst)); cbuf_mutex_unlock (dst); return (n); } int cbuf_copy (cbuf_t src, cbuf_t dst, int len, int *ndropped) { int n = 0; assert (src != NULL); assert (dst != NULL); if (ndropped) { *ndropped = 0; } if (src == dst) { errno = EINVAL; return (-1); } if (len < -1) { errno = EINVAL; return (-1); } if (len == 0) { return (0); } /* Lock cbufs in order of lowest memory address to prevent deadlock. */ if (src < dst) { cbuf_mutex_lock (src); cbuf_mutex_lock (dst); } else { cbuf_mutex_lock (dst); cbuf_mutex_lock (src); } assert (cbuf_is_valid (src)); assert (cbuf_is_valid (dst)); if (len == -1) { len = src->used; } if (len > 0) { n = cbuf_copier (src, dst, len, ndropped); } assert (cbuf_is_valid (src)); assert (cbuf_is_valid (dst)); cbuf_mutex_unlock (src); cbuf_mutex_unlock (dst); return (n); } int cbuf_move (cbuf_t src, cbuf_t dst, int len, int *ndropped) { int n = 0; assert (src != NULL); assert (dst != NULL); if (ndropped) { *ndropped = 0; } if (src == dst) { errno = EINVAL; return (-1); } if (len < -1) { errno = EINVAL; return (-1); } if (len == 0) { return (0); } /* Lock cbufs in order of lowest memory address to prevent deadlock. */ if (src < dst) { cbuf_mutex_lock (src); cbuf_mutex_lock (dst); } else { cbuf_mutex_lock (dst); cbuf_mutex_lock (src); } assert (cbuf_is_valid (src)); assert (cbuf_is_valid (dst)); if (len == -1) { len = src->used; } if (len > 0) { n = cbuf_copier (src, dst, len, ndropped); if (n > 0) { cbuf_dropper (src, n); } } assert (cbuf_is_valid (src)); assert (cbuf_is_valid (dst)); cbuf_mutex_unlock (src); cbuf_mutex_unlock (dst); return (n); } static int cbuf_find_replay_line (cbuf_t cb, int chars, int *nlines, int *nl) { /* Finds the specified number of lines from the replay region of the buffer. * If ([nlines] > 0), returns the number of bytes comprising the line count, * or 0 if this number of lines is not available (ie, all or none). * If ([nlines] == -1), returns the number of bytes comprising the maximum * line count bounded by the number of characters specified by [chars]. * Only complete lines (ie, those terminated by a newline) are counted, * with once exception: the most recent line of replay data is treated * as a complete line regardless of the presence of a terminating newline. * Sets the value-result parameter [nlines] to the number of lines found. * Sets [nl] to '1' if a newline is required to terminate the replay data. */ int i, n, m, l; int lines; assert (cb != NULL); assert (nlines != NULL); assert (*nlines >= -1); assert (cbuf_mutex_is_locked (cb)); n = m = l = 0; lines = *nlines; *nlines = 0; if (nl) { *nl = 0; /* init in case of early return */ } if ((lines == 0) || ((lines <= -1) && (chars <= 0))) { return (0); } if (cb->i_out == cb->i_rep) { return (0); /* no replay data available */ } if (lines > 0) { chars = -1; /* chars parm not used if lines > 0 */ } else { ++chars; /* incr to allow for preceding '\n' */ } /* Since the most recent line of replay data is considered implicitly * terminated, decrement the char count to account for the newline * if one is not present, or increment the line count if one is. * Note: cb->data[(O - 1 + (S+1)) % (S+1)] is the last replayable char. */ if (cb->data[(cb->i_out + cb->size) % (cb->size + 1)] != '\n') { if (nl) { *nl = 1; } --chars; } else { if (lines > 0) { ++lines; } --l; } i = cb->i_out; while (i != cb->i_rep) { i = (i + cb->size) % (cb->size + 1); /* (i - 1 + (S+1)) % (S+1) */ ++n; if (chars > 0) { --chars; } /* Complete lines are identified by a preceding newline. */ if (cb->data[i] == '\n') { if (lines > 0) { --lines; } m = n - 1; /* do not include preceding '\n' */ ++l; } if ((chars == 0) || (lines == 0)) { break; } } /* But the first line written in does not need a preceding newline. */ if ((!cb->got_wrap) && ((chars > 0) || (lines > 0))) { if (lines > 0) { --lines; } m = n; ++l; } if (lines > 0) { return (0); /* all or none, and not enough found */ } *nlines = l; return (m); } static int cbuf_find_unread_line (cbuf_t cb, int chars, int *nlines) { /* Finds the specified number of lines from the unread region of the buffer. * If ([nlines] > 0), returns the number of bytes comprising the line count, * or 0 if this number of lines is not available (ie, all or none). * If ([nlines] == -1), returns the number of bytes comprising the maximum * line count bounded by the number of characters specified by [chars]. * Only complete lines (ie, those terminated by a newline) are counted. * Sets the value-result parameter [nlines] to the number of lines found. */ int i, n, m, l; int lines; assert (cb != NULL); assert (nlines != NULL); assert (*nlines >= -1); assert (cbuf_mutex_is_locked (cb)); n = m = l = 0; lines = *nlines; *nlines = 0; if ((lines == 0) || ((lines <= -1) && (chars <= 0))) { return (0); } if (cb->used == 0) { return (0); /* no unread data available */ } if (lines > 0) { chars = -1; /* chars parm not used if lines > 0 */ } i = cb->i_out; while (i != cb->i_in) { ++n; if (chars > 0) { --chars; } if (cb->data[i] == '\n') { if (lines > 0) { --lines; } m = n; ++l; } if ((chars == 0) || (lines == 0)) { break; } i = (i + 1) % (cb->size + 1); } if (lines > 0) { return (0); /* all or none, and not enough found */ } *nlines = l; return (m); } static int cbuf_get_fd (void *dstbuf, int *psrcfd, int len) { /* Copies data from the file referenced by the file descriptor * pointed at by [psrcfd] into cbuf's [dstbuf]. * Returns the number of bytes read from the fd, 0 on EOF, or -1 on error. */ int n; assert (dstbuf != NULL); assert (psrcfd != NULL); assert (*psrcfd >= 0); assert (len > 0); do { n = read (*psrcfd, dstbuf, len); } while ((n < 0) && (errno == EINTR)); return (n); } static int cbuf_get_mem (void *dstbuf, unsigned char **psrcbuf, int len) { /* Copies data from the buffer pointed at by [psrcbuf] into cbuf's [dstbuf]. * Returns the number of bytes copied. */ assert (dstbuf != NULL); assert (psrcbuf != NULL); assert (*psrcbuf != NULL); assert (len > 0); memcpy (dstbuf, *psrcbuf, len); *psrcbuf += len; return (len); } static int cbuf_put_fd (void *srcbuf, int *pdstfd, int len) { /* Copies data from cbuf's [srcbuf] into the file referenced * by the file descriptor pointed at by [pdstfd]. * Returns the number of bytes written to the fd, or -1 on error. */ int n; assert (srcbuf != NULL); assert (pdstfd != NULL); assert (*pdstfd >= 0); assert (len > 0); do { n = write (*pdstfd, srcbuf, len); } while ((n < 0) && (errno == EINTR)); return (n); } static int cbuf_put_mem (void *srcbuf, unsigned char **pdstbuf, int len) { /* Copies data from cbuf's [srcbuf] into the buffer pointed at by [pdstbuf]. * Returns the number of bytes copied. */ assert (srcbuf != NULL); assert (pdstbuf != NULL); assert (*pdstbuf != NULL); assert (len > 0); memcpy (*pdstbuf, srcbuf, len); *pdstbuf += len; return (len); } static int cbuf_copier (cbuf_t src, cbuf_t dst, int len, int *ndropped) { /* Copies up to [len] bytes from the [src] cbuf into the [dst] cbuf. * Returns the number of bytes copied, or -1 on error (with errno set). * Sets [ndropped] (if not NULL) to the number of [dst] bytes overwritten. */ int ncopy, nfree, nleft, nrepl, n; int i_src, i_dst; assert (src != NULL); assert (dst != NULL); assert (len > 0); assert (cbuf_mutex_is_locked (src)); assert (cbuf_mutex_is_locked (dst)); /* Bound len by the number of bytes available. */ len = MIN (len, src->used); if (len == 0) { return (0); } /* Attempt to grow dst cbuf if necessary. */ nfree = dst->size - dst->used; if ((len > nfree) && (dst->size < dst->maxsize)) { nfree += cbuf_grow (dst, len - nfree); } /* Compute number of bytes to effectively copy to dst cbuf. */ if (dst->overwrite == CBUF_NO_DROP) { len = MIN (len, dst->size - dst->used); if (len == 0) { errno = ENOSPC; return (-1); } } else if (dst->overwrite == CBUF_WRAP_ONCE) { len = MIN (len, dst->size); } /* Compute number of bytes that will be overwritten in dst cbuf. */ if (ndropped) { *ndropped = MAX (0, len - dst->size + dst->used); } /* Compute number of bytes to physically copy to dst cbuf. This prevents * copying data that will overwritten if the cbuf wraps multiple times. */ ncopy = len; i_src = src->i_out; i_dst = dst->i_in; if (ncopy > dst->size) { n = ncopy - dst->size; i_src = (i_src + n) % (src->size + 1); ncopy -= n; } /* Copy data from src cbuf to dst cbuf. */ nleft = ncopy; while (nleft > 0) { n = MIN (((src->size + 1) - i_src), ((dst->size + 1) - i_dst)); n = MIN (n, nleft); memcpy (&dst->data[i_dst], &src->data[i_src], n); i_src = (i_src + n) % (src->size + 1); i_dst = (i_dst + n) % (dst->size + 1); nleft -= n; } /* Update dst cbuf metadata. */ if (ncopy > 0) { nrepl = (dst->i_out - dst->i_rep + (dst->size + 1)) % (dst->size + 1); dst->used = MIN (dst->used + ncopy, dst->size); assert (i_dst == (dst->i_in + ncopy) % (dst->size + 1)); dst->i_in = i_dst; if (ncopy > nfree - nrepl) { dst->got_wrap = 1; dst->i_rep = (dst->i_in + 1) % (dst->size + 1); } if (ncopy > nfree) { dst->i_out = dst->i_rep; } } return (len); } static int cbuf_dropper (cbuf_t cb, int len) { /* Discards exactly [len] bytes of unread data from [cb]. * Returns the number of bytes dropped. */ assert (cb != NULL); assert (len > 0); assert (len <= cb->used); assert (cbuf_mutex_is_locked (cb)); cb->used -= len; cb->i_out = (cb->i_out + len) % (cb->size + 1); /* Attempt to shrink cbuf if possible. */ if ((cb->size - cb->used > CBUF_CHUNK) && (cb->size > cb->minsize)) { cbuf_shrink (cb); } /* Don't call me clumsy, don't call me a fool. * When things fall down on me, I'm following the rule. */ return (len); } static int cbuf_reader (cbuf_t src, int len, cbuf_iof putf, void *dst) { /* Reads up to [len] bytes from [src] into the object pointed at by [dst]. * The I/O function [putf] specifies how data is written into [dst]. * Returns the number of bytes read, or -1 on error (with errno set). * Note that [dst] is a value-result parameter and will be "moved forward" * by the number of bytes written into it. */ int nleft, n, m; int i_src; assert (src != NULL); assert (len > 0); assert (putf != NULL); assert (dst != NULL); assert (cbuf_mutex_is_locked (src)); /* Bound len by the number of bytes available. */ len = MIN (len, src->used); if (len == 0) { return (0); } /* Copy data from src cbuf to dst obj. Do the cbuf hokey-pokey and * wrap-around the buffer at most once. Break out if putf() returns * either an ERR or a short count. */ i_src = src->i_out; nleft = len; m = 0; while (nleft > 0) { n = MIN (nleft, (src->size + 1) - i_src); m = putf (&src->data[i_src], dst, n); if (m > 0) { nleft -= m; i_src = (i_src + m) % (src->size + 1); } if (n != m) { break; /* got ERR or "short" putf() */ } } /* Compute number of bytes written to dst obj. */ n = len - nleft; assert ((n >= 0) && (n <= len)); /* * If no data has been written, return the ERR reported by putf(). */ if (n == 0) { return (m); } return (n); } static int cbuf_replayer (cbuf_t src, int len, cbuf_iof putf, void *dst) { /* Replays up to [len] bytes from [src] into the object pointed at by [dst]. * The I/O function [putf] specifies how data is written into [dst]. * Returns the number of bytes replayed, or -1 on error (with errno set). * Note that [dst] is a value-result parameter and will be "moved forward" * by the number of bytes written into it. */ int nleft, n, m; int i_src; assert (src != NULL); assert (len > 0); assert (putf != NULL); assert (dst != NULL); assert (cbuf_mutex_is_locked (src)); /* Bound len by the number of bytes available. */ n = (src->i_out - src->i_rep + (src->size + 1)) % (src->size + 1); len = MIN (len, n); if (len == 0) { return (0); } /* Copy data from src cbuf to dst obj. Do the cbuf hokey-pokey and * wrap-around the buffer at most once. Break out if putf() returns * either an ERR or a short count. */ i_src = (src->i_out - len + (src->size + 1)) % (src->size + 1); nleft = len; m = 0; while (nleft > 0) { n = MIN (nleft, (src->size + 1) - i_src); m = putf (&src->data[i_src], dst, n); if (m > 0) { nleft -= m; i_src = (i_src + m) % (src->size + 1); } if (n != m) { break; /* got ERR or "short" putf() */ } } /* Compute number of bytes written to dst obj. */ n = len - nleft; assert ((n >= 0) && (n <= len)); /* * If no data has been written, return the ERR reported by putf(). */ if (n == 0) { return (m); } return (n); } static int cbuf_writer (cbuf_t dst, int len, cbuf_iof getf, void *src, int *ndropped) { /* Writes up to [len] bytes from the object pointed at by [src] into [dst]. * The I/O function [getf] specifies how data is read from [src]. * Returns the number of bytes written, or -1 on error (with errno set). * Sets [ndropped] (if not NULL) to the number of [dst] bytes overwritten. * Note that [src] is a value-result parameter and will be "moved forward" * by the number of bytes read from it. */ int nfree, nleft, nrepl, n, m; int i_dst; assert (dst != NULL); assert (len > 0); assert (getf != NULL); assert (src != NULL); assert (cbuf_mutex_is_locked (dst)); /* Attempt to grow dst cbuf if necessary. */ nfree = dst->size - dst->used; if ((len > nfree) && (dst->size < dst->maxsize)) { nfree += cbuf_grow (dst, len - nfree); } /* Compute number of bytes to write to dst cbuf. */ if (dst->overwrite == CBUF_NO_DROP) { len = MIN (len, dst->size - dst->used); if (len == 0) { errno = ENOSPC; return (-1); } } else if (dst->overwrite == CBUF_WRAP_ONCE) { len = MIN (len, dst->size); } /* Copy data from src obj to dst cbuf. Do the cbuf hokey-pokey and * wrap-around the buffer as needed. Break out if getf() returns * either an EOF/ERR or a short count. */ i_dst = dst->i_in; nleft = len; m = 0; while (nleft > 0) { n = MIN (nleft, (dst->size + 1) - i_dst); m = getf (&dst->data[i_dst], src, n); if (m > 0) { nleft -= m; i_dst = (i_dst + m) % (dst->size + 1); } if (n != m) { break; /* got EOF/ERR or "short" getf() */ } } /* Compute number of bytes written to dst cbuf. */ n = len - nleft; assert ((n >= 0) && (n <= len)); /* * If no data has been written, return the EOF/ERR reported by getf(). */ if (n == 0) { return (m); } /* Update dst cbuf metadata. */ if (n > 0) { nrepl = (dst->i_out - dst->i_rep + (dst->size + 1)) % (dst->size + 1); dst->used = MIN (dst->used + n, dst->size); assert (i_dst == (dst->i_in + n) % (dst->size + 1)); dst->i_in = i_dst; if (n > nfree - nrepl) { dst->got_wrap = 1; dst->i_rep = (dst->i_in + 1) % (dst->size + 1); } if (n > nfree) { dst->i_out = dst->i_rep; } } if (ndropped) { *ndropped = MAX (0, n - nfree); } return (n); } static int cbuf_grow (cbuf_t cb, int n) { /* Attempts to grow the circular buffer [cb] by at least [n] bytes. * Returns the number of bytes by which the buffer has grown (which may be * less-than, equal-to, or greater-than the number of bytes requested). */ unsigned char *data; int size_old, size_meta; int m; assert (cb != NULL); assert (n > 0); assert (cbuf_mutex_is_locked (cb)); if (cb->size == cb->maxsize) { return (0); } size_old = cb->size; size_meta = cb->alloc - cb->size; /* size of sentinel & magic cookies */ assert (size_meta > 0); /* Attempt to grow data buffer by multiples of the chunk-size. */ m = cb->alloc + n; m = m + (CBUF_CHUNK - (m % CBUF_CHUNK)); m = MIN (m, (cb->maxsize + size_meta)); assert (m > cb->alloc); data = cb->data; #ifndef NDEBUG data -= CBUF_MAGIC_LEN; /* jump back to what malloc returned */ #endif /* !NDEBUG */ if (!(data = realloc (data, m))) { /* * XXX: Set flag or somesuch to prevent regrowing when out of memory? */ return (0); /* unable to grow data buffer */ } cb->data = data; cb->alloc = m; cb->size = m - size_meta; #ifndef NDEBUG /* A round cookie with one bite out of it looks like a C. * The underflow cookie will have been copied by realloc() if needed. * But the overflow cookie must be rebaked. * Must use memcpy since overflow cookie may not be word-aligned. */ cb->data += CBUF_MAGIC_LEN; /* jump forward past underflow magic */ memcpy (cb->data + cb->size + 1, (void *) &cb->magic, CBUF_MAGIC_LEN); #endif /* !NDEBUG */ /* The memory containing replay and unread data must be contiguous modulo * the buffer size. Additional memory must be inserted between where * new data is written in (i_in) and where replay data starts (i_rep). * If replay data wraps-around the old buffer, move it to the new end * of the buffer so it wraps-around in the same manner. */ if (cb->i_rep > cb->i_in) { n = (size_old + 1) - cb->i_rep; m = (cb->size + 1) - n; memmove (cb->data + m, cb->data + cb->i_rep, n); if (cb->i_out >= cb->i_rep) { cb->i_out += m - cb->i_rep; } cb->i_rep = m; } assert (cbuf_is_valid (cb)); return (cb->size - size_old); } static int cbuf_shrink (cbuf_t cb) { /* XXX: DOCUMENT ME. */ assert (cb != NULL); assert (cbuf_mutex_is_locked (cb)); assert (cbuf_is_valid (cb)); if (cb->size == cb->minsize) { return (0); } if (cb->size - cb->used <= CBUF_CHUNK) { return (0); } /* FIXME: NOT IMPLEMENTED. */ assert (cbuf_is_valid (cb)); return (0); } #ifndef NDEBUG #ifdef WITH_PTHREADS static int cbuf_mutex_is_locked (cbuf_t cb) { /* Returns true if the mutex is locked; o/w, returns false. */ int rc; assert (cb != NULL); rc = pthread_mutex_trylock (&cb->mutex); return (rc == EBUSY ? 1 : 0); } #endif /* WITH_PTHREADS */ #endif /* !NDEBUG */ #ifndef NDEBUG static int cbuf_is_valid (cbuf_t cb) { /* Validates the data structure. All invariants should be tested here. * Returns true if everything is valid; o/w, aborts due to assertion failure. */ int nfree; assert (cb != NULL); assert (cbuf_mutex_is_locked (cb)); assert (cb->data != NULL); assert (cb->magic == CBUF_MAGIC); /* * Must use memcmp since overflow cookie may not be word-aligned. */ assert (memcmp (cb->data - CBUF_MAGIC_LEN, (void *) &cb->magic, CBUF_MAGIC_LEN) == 0); assert (memcmp (cb->data + cb->size + 1, (void *) &cb->magic, CBUF_MAGIC_LEN) == 0); assert (cb->alloc > 0); assert (cb->alloc > cb->size); assert (cb->size > 0); assert (cb->size >= cb->minsize); assert (cb->size <= cb->maxsize); assert (cb->minsize > 0); assert (cb->maxsize > 0); assert (cb->used >= 0); assert (cb->used <= cb->size); assert (cb->overwrite == CBUF_NO_DROP || cb->overwrite == CBUF_WRAP_ONCE || cb->overwrite == CBUF_WRAP_MANY); assert (cb->got_wrap || !cb->i_rep);/* i_rep = 0 if data has not wrapped */ assert (cb->i_in >= 0); assert (cb->i_in <= cb->size); assert (cb->i_out >= 0); assert (cb->i_out <= cb->size); assert (cb->i_rep >= 0); assert (cb->i_rep <= cb->size); if (cb->i_in >= cb->i_out) { assert ((cb->i_rep > cb->i_in) || (cb->i_rep <= cb->i_out)); } else /* if (cb->in < cb->i_out) */ { assert ((cb->i_rep > cb->i_in) && (cb->i_rep <= cb->i_out)); } nfree = (cb->i_out - cb->i_in - 1 + (cb->size + 1)) % (cb->size + 1); assert (cb->size - cb->used == nfree); return (1); } #endif /* !NDEBUG */ powerman-2.4.4/src/liblsd/cbuf.h000066400000000000000000000320101467035776500165210ustar00rootroot00000000000000/***************************************************************************** * Copyright (C) 2002-2005 The Regents of the University of California. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). * Written by Chris Dunlap . * * This file is from LSD-Tools, the LLNL Software Development Toolbox. * * LSD-Tools 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. * * LSD-Tools is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with LSD-Tools; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *****************************************************************************/ #ifndef LSD_CBUF_H #define LSD_CBUF_H /***************************************************************************** * Notes *****************************************************************************/ /* * Cbuf is a circular-buffer capable of dynamically resizing itself. * Unread data in the buffer will be overwritten once the cbuf has * reached its maximum size or is unable to allocate additional memory. * * The CBUF_OPT_OVERWRITE option specifies how unread cbuf data will * be overwritten. If set to CBUF_NO_DROP, unread data will never be * overwritten; writes into the cbuf will return -1 with ENOSPC. If set * to CBUF_WRAP_ONCE, a single write operation will wrap-around the buffer * at most once, and up to cbuf_used() bytes of data may be overwritten. * If set to CBUF_WRAP_MANY, a single write operation will wrap-around the * buffer as many times as needed in order to write all of the data. * * If NDEBUG is not defined, internal debug code will be enabled. This is * intended for development use only and production code should define NDEBUG. * * If WITH_LSD_FATAL_ERROR_FUNC is defined, the linker will expect to * find an external lsd_fatal_error(file,line,mesg) function. By default, * lsd_fatal_error(file,line,mesg) is a macro definition that outputs an * error message to stderr. This macro may be redefined to invoke another * routine instead. * * If WITH_LSD_NOMEM_ERROR_FUNC is defined, the linker will expect to * find an external lsd_nomem_error(file,line,mesg) function. By default, * lsd_nomem_error(file,line,mesg) is a macro definition that returns NULL. * This macro may be redefined to invoke another routine instead. * * If WITH_PTHREADS is defined, these routines will be thread-safe. */ /***************************************************************************** * Data Types *****************************************************************************/ typedef struct cbuf * cbuf_t; /* circular-buffer opaque data type */ typedef enum { /* cbuf option names */ CBUF_OPT_OVERWRITE } cbuf_opt_t; typedef enum { /* CBUF_OPT_OVERWRITE values: */ CBUF_NO_DROP, /* -never drop data, ENOSPC if full */ CBUF_WRAP_ONCE, /* -drop data, wrapping at most once */ CBUF_WRAP_MANY /* -drop data, wrapping as needed */ } cbuf_overwrite_t; /***************************************************************************** * Functions *****************************************************************************/ cbuf_t cbuf_create (int minsize, int maxsize); /* * Creates and returns a new circular buffer, or lsd_nomem_error() on failure. * The buffer is initially allocated to hold [minsize] bytes of data, * but can attempt to grow up to [maxsize] bytes before overwriting data. * Set minsize = maxsize to prevent cbuf from dynamically resizing itself. * The default overwrite option behavior is CBUF_WRAP_MANY. * Abandoning a cbuf without calling cbuf_destroy() will cause a memory leak. */ void cbuf_destroy (cbuf_t cb); /* * Destroys the circular buffer [cb]. */ void cbuf_flush (cbuf_t cb); /* * Flushes all data (including replay data) in [cb]. */ int cbuf_size (cbuf_t cb); /* * Returns the maximum size of the buffer allocated to [cb] * (ie, the number of bytes it can currently hold). */ int cbuf_free (cbuf_t cb); /* * Returns the number of bytes in [cb] available for writing before unread * data is overwritten (assuming the cbuf can resize itself if needed). */ int cbuf_used (cbuf_t cb); /* * Returns the number of bytes in [cb] available for reading. */ int cbuf_lines_used (cbuf_t cb); /* * Returns the number of lines in [cb] available for reading. */ int cbuf_reused (cbuf_t cb); /* * Returns the number of bytes in [cb] available for replaying/rewinding. */ int cbuf_lines_reused (cbuf_t cb); /* * Returns the number of lines in [cb] available for replaying/rewinding. */ int cbuf_is_empty (cbuf_t cb); /* * Returns non-zero if [cb] is empty; o/w, returns zero. */ int cbuf_opt_get (cbuf_t cb, cbuf_opt_t name, int *value); /* * Gets the [name] option for [cb] and sets [value] to the result. * Returns 0 on success, or -1 on error (with errno set). */ int cbuf_opt_set (cbuf_t cb, cbuf_opt_t name, int value); /* * Sets the [name] option for [cb] to [value]. * Returns 0 on success, or -1 on error (with errno set). */ int cbuf_drop (cbuf_t src, int len); /* * Discards up to [len] bytes of unread data from [src]; * if [len] is -1, all unread data will be dropped. * Dropped data is still available via the replay buffer. * Returns the number of bytes dropped, or -1 on error (with errno set). */ int cbuf_peek (cbuf_t src, void *dstbuf, int len); /* * Reads up to [len] bytes of data from the [src] cbuf into [dstbuf], * but does not consume the data read from the cbuf. * The "peek" can be committed to the cbuf via a call to cbuf_drop(), * but the peek+drop combination is not atomic. * Returns the number of bytes read, or -1 on error (with errno set). */ int cbuf_read (cbuf_t src, void *dstbuf, int len); /* * Reads up to [len] bytes of data from the [src] cbuf into [dstbuf]. * Returns the number of bytes read, or -1 on error (with errno set). */ int cbuf_replay (cbuf_t src, void *dstbuf, int len); /* * Replays up to [len] bytes of previously read data from the [src] cbuf * into [dstbuf]. * Returns the number of bytes replayed, or -1 on error (with errno set). */ int cbuf_rewind (cbuf_t src, int len); /* * Rewinds [src] by up to [len] bytes, placing previously read data back in * the unread data buffer; if [len] is -1, all replay data will be rewound. * Returns the number of bytes rewound, or -1 on error (with errno set). */ int cbuf_write (cbuf_t dst, void *srcbuf, int len, int *ndropped); /* * Writes up to [len] bytes of data from [srcbuf] into the [dst] cbuf * according to dst's CBUF_OPT_OVERWRITE behavior. * Returns the number of bytes written, or -1 on error (with errno set). * Sets [ndropped] (if not NULL) to the number of bytes overwritten. */ int cbuf_drop_line (cbuf_t src, int len, int lines); /* * Discards the specified [lines] of data from [src]. If [lines] is -1, * discards the maximum number of lines comprised of up to [len] characters. * Dropped data is still available via the replay buffer. * Returns the number of bytes dropped, or -1 on error (with errno set). * Returns 0 if the number of lines is not available (ie, all or none). */ int cbuf_peek_line (cbuf_t src, char *dstbuf, int len, int lines); /* * Reads the specified [lines] of data from the [src] cbuf into [dstbuf], * but does not consume the data read from the cbuf. If [lines] is -1, * reads the maximum number of lines that [dstbuf] can hold. The buffer * will be NUL-terminated and contain at most ([len] - 1) characters. * The "peek" can be committed to the cbuf via a call to cbuf_drop(), * but the peek+drop combination is not atomic. * Returns strlen of the line(s) on success; truncation occurred if >= [len]. * Returns 0 if the number of lines is not available (ie, all or none). * Returns -1 on error (with errno set). */ int cbuf_read_line (cbuf_t src, char *dstbuf, int len, int lines); /* * Reads the specified [lines] of data from the [src] cbuf into [dstbuf]. * If [lines] is -1, reads the maximum number of lines that [dstbuf] * can hold. The buffer will be NUL-terminated and contain at most * ([len] - 1) characters. * Returns strlen of the line(s) on success; truncation occurred if >= [len], * in which case excess line data is discarded. Returns 0 if the number * of lines is not available (ie, all or none), in which case no data is * consumed. Returns -1 on error (with errno set). */ int cbuf_replay_line (cbuf_t src, char *dstbuf, int len, int lines); /* * Replays the specified [lines] of data from the [src] cbuf into [dstbuf]. * If [lines] is -1, replays the maximum number of lines that [dstbuf] * can hold. A newline will be appended to [dstbuf] if the last (ie, most * recently read) line does not contain a trailing newline. The buffer * will be NUL-terminated and contain at most ([len] - 1) characters. * Returns strlen of the line(s) on success; truncation occurred if >= [len]. * Returns 0 if the number of lines is not available (ie, all or none). * Returns -1 on error (with errno set). */ int cbuf_rewind_line (cbuf_t src, int len, int lines); /* * Rewinds [src] by the specified [lines] of data, placing previously read * data back in the unread data buffer. If [lines] is -1, rewinds the * maximum number of lines comprised of up to [len] characters. * Returns the number of bytes rewound, or -1 on error (with errno set). * Returns 0 if the number of lines is not available (ie, all or none). */ int cbuf_write_line (cbuf_t dst, char *srcbuf, int *ndropped); /* * Writes the entire NUL-terminated [srcbuf] string into the [dst] cbuf * according to dst's CBUF_OPT_OVERWRITE behavior. A newline will be * appended to the cbuf if [srcbuf] does not contain a trailing newline. * Returns the number of bytes written, or -1 or error (with errno set). * Sets [ndropped] (if not NULL) to the number of bytes overwritten. */ int cbuf_peek_to_fd (cbuf_t src, int dstfd, int len); /* * Reads up to [len] bytes of data from the [src] cbuf into the file * referenced by the [dstfd] file descriptor, but does not consume the * data read from the cbuf. If [len] is -1, it will be set to the number * of [src] bytes available for reading. * The "peek" can be committed to the cbuf via a call to cbuf_drop(), * but the peek+drop combination is not atomic. * Returns the number of bytes read, or -1 on error (with errno set). */ int cbuf_read_to_fd (cbuf_t src, int dstfd, int len); /* * Reads up to [len] bytes of data from the [src] cbuf into the file * referenced by the [dstfd] file descriptor. If [len] is -1, it will * be set to the number of [src] bytes available for reading. * Returns the number of bytes read, or -1 on error (with errno set). */ int cbuf_replay_to_fd (cbuf_t src, int dstfd, int len); /* * Replays up to [len] bytes of previously read data from the [src] cbuf into * the file referenced by the [dstfd] file descriptor. If [len] is -1, it * will be set to the maximum number of [src] bytes available for replay. * Returns the number of bytes replayed, or -1 on error (with errno set). */ int cbuf_write_from_fd (cbuf_t dst, int srcfd, int len, int *ndropped); /* * Writes up to [len] bytes of data from the file referenced by the * [srcfd] file descriptor into the [dst] cbuf according to dst's * CBUF_OPT_OVERWRITE behavior. If [len] is -1, it will be set to * an appropriate chunk size. * Returns the number of bytes written, 0 on EOF, or -1 on error (with errno). * Sets [ndropped] (if not NULL) to the number of bytes overwritten. */ int cbuf_copy (cbuf_t src, cbuf_t dst, int len, int *ndropped); /* * Copies up to [len] bytes of data from the [src] cbuf into the [dst] cbuf * according to dst's CBUF_OPT_OVERWRITE behavior. If [len] is -1, * it will be set to the number of [src] bytes available for reading. * Returns the number of bytes copied, or -1 on error (with errno set). * Sets [ndropped] (if not NULL) to the number of [dst] bytes overwritten. */ int cbuf_move (cbuf_t src, cbuf_t dst, int len, int *ndropped); /* * Moves up to [len] bytes of data from the [src] cbuf into the [dst] cbuf * according to dst's CBUF_OPT_OVERWRITE behavior. If [len] is -1, * it will be set to the number of [src] bytes available for reading. * Returns the number of bytes moved, or -1 on error (with errno set). * Sets [ndropped] (if not NULL) to the number of [dst] bytes overwritten. */ #endif /* !LSD_CBUF_H */ powerman-2.4.4/src/liblsd/hash.c000066400000000000000000000264471467035776500165410ustar00rootroot00000000000000/***************************************************************************** * Copyright (C) 2003 The Regents of the University of California. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). * Written by Chris Dunlap . * * This file is from LSD-Tools, the LLNL Software Development Toolbox. * * LSD-Tools 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. * * LSD-Tools is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with LSD-Tools; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***************************************************************************** * Refer to "hash.h" for documentation on public functions. *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #if WITH_PTHREADS #include "thread.h" #else # define lsd_mutex_init(mutex) # define lsd_mutex_lock(mutex) # define lsd_mutex_unlock(mutex) # define lsd_mutex_destroy(mutex) # define lsd_mutex_is_locked(mutex) (1) #endif #include "hash.h" /***************************************************************************** * Constants *****************************************************************************/ #define HASH_ALLOC 256 #define HASH_DEF_SIZE 1213 #define HASH_MAGIC 0xDEADBEEF /***************************************************************************** * Data Types *****************************************************************************/ struct hash_node { struct hash_node *next; /* next node in list */ void *data; /* ptr to hashed item */ const void *hkey; /* ptr to hashed item's key */ }; struct hash { int count; /* number of items in hash table */ int size; /* num slots allocated in hash table */ struct hash_node **table; /* hash table array of node ptrs */ hash_cmp_f cmp_f; /* key comparison function */ hash_del_f del_f; /* item deletion function */ hash_key_f key_f; /* key hash function */ #if WITH_PTHREADS pthread_mutex_t mutex; /* mutex to protect access to hash */ #endif /* WITH_PTHREADS */ #ifndef NDEBUG unsigned int magic; /* sentinel for asserting validity */ #endif /* NDEBUG */ }; /***************************************************************************** * Prototypes *****************************************************************************/ static struct hash_node * hash_node_alloc (void); static void hash_node_free (struct hash_node *node); /***************************************************************************** * Variables *****************************************************************************/ static struct hash_node *hash_free_list = NULL; #if WITH_PTHREADS static pthread_mutex_t hash_free_lock = PTHREAD_MUTEX_INITIALIZER; #endif /* WITH_PTHREADS */ /***************************************************************************** * Macros *****************************************************************************/ #ifdef WITH_LSD_FATAL_ERROR_FUNC # undef lsd_fatal_error extern void lsd_fatal_error (char *file, int line, char *mesg); #else /* !WITH_LSD_FATAL_ERROR_FUNC */ # ifndef lsd_fatal_error # define lsd_fatal_error(file, line, mesg) (abort ()) # endif /* !lsd_fatal_error */ #endif /* !WITH_LSD_FATAL_ERROR_FUNC */ #ifdef WITH_LSD_NOMEM_ERROR_FUNC # undef lsd_nomem_error extern void * lsd_nomem_error (char *file, int line, char *mesg); #else /* !WITH_LSD_NOMEM_ERROR_FUNC */ # ifndef lsd_nomem_error # define lsd_nomem_error(file, line, mesg) (NULL) # endif /* !lsd_nomem_error */ #endif /* !WITH_LSD_NOMEM_ERROR_FUNC */ /***************************************************************************** * Functions *****************************************************************************/ hash_t hash_create (int size, hash_key_f key_f, hash_cmp_f cmp_f, hash_del_f del_f) { hash_t h; if (!cmp_f || !key_f) { errno = EINVAL; return (NULL); } if (size <= 0) { size = HASH_DEF_SIZE; } if (!(h = malloc (sizeof (*h)))) { return (lsd_nomem_error (__FILE__, __LINE__, "hash_create")); } if (!(h->table = calloc (size, sizeof (struct hash_node *)))) { free (h); return (lsd_nomem_error (__FILE__, __LINE__, "hash_create")); } h->count = 0; h->size = size; h->cmp_f = cmp_f; h->del_f = del_f; h->key_f = key_f; lsd_mutex_init (&h->mutex); assert (h->magic = HASH_MAGIC); /* set magic via assert abuse */ return (h); } void hash_destroy (hash_t h) { int i; struct hash_node *p, *q; assert (h != NULL); lsd_mutex_lock (&h->mutex); assert (h->magic == HASH_MAGIC); for (i = 0; i < h->size; i++) { for (p = h->table[i]; p != NULL; p = q) { q = p->next; if (h->del_f) h->del_f (p->data); hash_node_free (p); } } assert (h->magic = ~HASH_MAGIC); /* clear magic via assert abuse */ lsd_mutex_unlock (&h->mutex); lsd_mutex_destroy (&h->mutex); free (h->table); free (h); return; } int hash_is_empty (hash_t h) { int n; assert (h != NULL); lsd_mutex_lock (&h->mutex); assert (h->magic == HASH_MAGIC); n = h->count; lsd_mutex_unlock (&h->mutex); return (n == 0); } int hash_count (hash_t h) { int n; assert (h != NULL); lsd_mutex_lock (&h->mutex); assert (h->magic == HASH_MAGIC); n = h->count; lsd_mutex_unlock (&h->mutex); return (n); } void * hash_find (hash_t h, const void *key) { unsigned int slot; struct hash_node *p; void *data = NULL; assert (h != NULL); if (!key) { errno = EINVAL; return (NULL); } errno = 0; lsd_mutex_lock (&h->mutex); assert (h->magic == HASH_MAGIC); slot = h->key_f (key) % h->size; for (p = h->table[slot]; p != NULL; p = p->next) { if (!h->cmp_f (p->hkey, key)) { data = p->data; break; } } lsd_mutex_unlock (&h->mutex); return (data); } void * hash_insert (hash_t h, const void *key, void *data) { struct hash_node *p; unsigned int slot; assert (h != NULL); if (!key || !data) { errno = EINVAL; return (NULL); } lsd_mutex_lock (&h->mutex); assert (h->magic == HASH_MAGIC); slot = h->key_f (key) % h->size; for (p = h->table[slot]; p != NULL; p = p->next) { if (!h->cmp_f (p->hkey, key)) { errno = EEXIST; data = NULL; goto end; } } if (!(p = hash_node_alloc())) { data = lsd_nomem_error (__FILE__, __LINE__, "hash_insert"); goto end; } p->hkey = key; p->data = data; p->next = h->table[slot]; h->table[slot] = p; h->count++; end: lsd_mutex_unlock (&h->mutex); return (data); } void * hash_remove (hash_t h, const void *key) { struct hash_node **pp; struct hash_node *p; unsigned int slot; void *data = NULL; assert (h != NULL); if (!key) { errno = EINVAL; return (NULL); } errno = 0; lsd_mutex_lock (&h->mutex); assert (h->magic == HASH_MAGIC); slot = h->key_f (key) % h->size; for (pp = &(h->table[slot]); (p = *pp) != NULL; pp = &((*pp)->next)) { if (!h->cmp_f (p->hkey, key)) { data = p->data; *pp = p->next; hash_node_free (p); h->count--; break; } } lsd_mutex_unlock (&h->mutex); return (data); } int hash_delete_if (hash_t h, hash_arg_f arg_f, void *arg) { int i; struct hash_node **pp; struct hash_node *p; int n = 0; assert (h != NULL); if (!arg_f) { errno = EINVAL; return (-1); } lsd_mutex_lock (&h->mutex); assert (h->magic == HASH_MAGIC); for (i = 0; i < h->size; i++) { pp = &(h->table[i]); while ((p = *pp) != NULL) { if (arg_f (p->data, arg) > 0) { if (h->del_f) h->del_f (p->data); *pp = p->next; hash_node_free (p); h->count--; n++; } else { pp = &(p->next); } } } lsd_mutex_unlock (&h->mutex); return (n); } int hash_for_each (hash_t h, hash_arg_f arg_f, void *arg) { int i; struct hash_node *p; int n = 0; assert (h != NULL); if (!arg_f) { errno = EINVAL; return (-1); } lsd_mutex_lock (&h->mutex); assert (h->magic == HASH_MAGIC); for (i = 0; i < h->size; i++) { for (p = h->table[i]; p != NULL; p = p->next) { if (arg_f (p->data, arg) > 0) { n++; } } } lsd_mutex_unlock (&h->mutex); return (n); } /***************************************************************************** * Hash Functions *****************************************************************************/ unsigned int hash_key_string (const char *str) { unsigned char *p; unsigned int hval = 0; const unsigned int multiplier = 31; for (p = (unsigned char *) str; *p != '\0'; p++) { hval += (multiplier * hval) + *p; } return (hval); } /***************************************************************************** * Internal Functions *****************************************************************************/ static struct hash_node * hash_node_alloc (void) { /* Allocates a hash node from the freelist. * Memory is allocated in chunks of HASH_ALLOC. * Returns a ptr to the object, or NULL if memory allocation fails. */ int i; struct hash_node *p = NULL; assert (HASH_ALLOC > 0); lsd_mutex_lock (&hash_free_lock); if (!hash_free_list) { if ((hash_free_list = malloc (HASH_ALLOC * sizeof (*p)))) { for (i = 0; i < HASH_ALLOC - 1; i++) hash_free_list[i].next = &hash_free_list[i+1]; hash_free_list[i].next = NULL; } } if (hash_free_list) { p = hash_free_list; hash_free_list = p->next; } else { errno = ENOMEM; } lsd_mutex_unlock (&hash_free_lock); return (p); } static void hash_node_free (struct hash_node *node) { /* De-allocates the object [node], returning it to the freelist. */ assert (node != NULL); memset (node, 0, sizeof (*node)); lsd_mutex_lock (&hash_free_lock); node->next = hash_free_list; hash_free_list = node; lsd_mutex_unlock (&hash_free_lock); return; } powerman-2.4.4/src/liblsd/hash.h000066400000000000000000000153171467035776500165400ustar00rootroot00000000000000/***************************************************************************** * Copyright (C) 2003 The Regents of the University of California. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). * Written by Chris Dunlap . * * This file is from LSD-Tools, the LLNL Software Development Toolbox. * * LSD-Tools 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. * * LSD-Tools is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with LSD-Tools; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *****************************************************************************/ #ifndef LSD_HASH_H #define LSD_HASH_H /***************************************************************************** * Notes *****************************************************************************/ /* * If an item's key is modified after insertion, the hash will be unable to * locate it if the new key should hash to a different slot in the table. * * If NDEBUG is not defined, internal debug code will be enabled; this is * intended for development use only. Production code should define NDEBUG. * * If WITH_LSD_FATAL_ERROR_FUNC is defined, the linker will expect to * find an external lsd_fatal_error(file,line,mesg) function. By default, * lsd_fatal_error(file,line,mesg) is a macro definition that aborts. * This macro may be redefined to invoke another routine instead. * * If WITH_LSD_NOMEM_ERROR_FUNC is defined, the linker will expect to * find an external lsd_nomem_error(file,line,mesg) function. By default, * lsd_nomem_error(file,line,mesg) is a macro definition that returns NULL. * This macro may be redefined to invoke another routine instead. * * If WITH_PTHREADS is defined, these routines will be thread-safe. */ /***************************************************************************** * Data Types *****************************************************************************/ typedef struct hash * hash_t; /* * Hash table opaque data type. */ typedef unsigned int (*hash_key_f) (const void *key); /* * Function prototype for the hash function responsible for converting * the data's [key] into an unsigned integer hash value. */ typedef int (*hash_cmp_f) (const void *key1, const void *key2); /* * Function prototype for comparing two keys. * Returns zero if both keys are equal; o/w, returns nonzero. */ typedef void (*hash_del_f) (void *data); /* * Function prototype for de-allocating a data item stored within a hash. * This function is responsible for freeing all memory associated with * the [data] item, including any subordinate items. */ typedef int (*hash_arg_f) (void *data, void *arg); /* * Function prototype for operating on each element in the hash table. * The function will be invoked once for each [data] item in the hash, * with [arg] being passed in as an argument. */ /***************************************************************************** * Functions *****************************************************************************/ hash_t hash_create (int size, hash_key_f key_f, hash_cmp_f cmp_f, hash_del_f del_f); /* * Creates and returns a new hash table on success. * Returns lsd_nomem_error() with errno=ENOMEM if memory allocation fails. * Returns NULL with errno=EINVAL if [keyf] or [cmpf] is not specified. * The [size] is the number of slots in the table; a larger table requires * more memory, but generally provide quicker access times. If set <= 0, * the default size is used. * The [keyf] function converts a key into a hash value. * The [cmpf] function determines whether two keys are equal. * The [delf] function de-allocates memory used by items in the hash; * if set to NULL, memory associated with these items will not be freed * when the hash is destroyed. */ void hash_destroy (hash_t h); /* * Destroys hash table [h]. If a deletion function was specified when the * hash was created, it will be called for each item contained within. * Abadoning a hash without calling hash_destroy() will cause a memory leak. */ int hash_is_empty (hash_t h); /* * Returns non-zero if hash table [h] is empty; o/w, returns zero. */ int hash_count (hash_t h); /* * Returns the number of items in hash table [h]. */ void * hash_find (hash_t h, const void *key); /* * Searches for the item corresponding to [key] in hash table [h]. * Returns a ptr to the found item's data on success. * Returns NULL with errno=0 if no matching item is found. * Returns NULL with errno=EINVAL if [key] is not specified. */ void * hash_insert (hash_t h, const void *key, void *data); /* * Inserts [data] with the corresponding [key] into hash table [h]; * note that it is permissible for [key] to be set equal to [data]. * Returns a ptr to the inserted item's data on success. * Returns NULL with errno=EEXIST if [key] already exists in the hash. * Returns NULL with errno=EINVAL if [key] or [data] is not specified. * Returns lsd_nomem_error() with errno=ENOMEM if memory allocation fails. */ void * hash_remove (hash_t h, const void *key); /* * Removes the item corresponding to [key] from hash table [h]. * Returns a ptr to the removed item's data on success. * Returns NULL with errno=0 if no matching item is found. * Returns NULL with errno=EINVAL if [key] is not specified. */ int hash_delete_if (hash_t h, hash_arg_f argf, void *arg); /* * Conditionally deletes (and de-allocates) items from hash table [h]. * The [argf] function is invoked once for each item in the hash, with * [arg] being passed in as an argument. Items for which [argf] returns * greater-than-zero are deleted. * Returns the number of items deleted. * Returns -1 with errno=EINVAL if [argf] is not specified. */ int hash_for_each (hash_t h, hash_arg_f argf, void *arg); /* * Invokes the [argf] function once for each item in hash table [h], * with [arg] being passed in as an argument. * Returns the number of items for which [argf] returns greater-than-zero. * Returns -1 with errno=EINVAL if [argf] is not specified. */ unsigned int hash_key_string (const char *str); /* * A hash_key_f function that hashes the string [str]. */ #endif /* !LSD_HASH_H */ powerman-2.4.4/src/liblsd/hostlist.c000066400000000000000000002126111467035776500174550ustar00rootroot00000000000000/*****************************************************************************\ * $LSDId: commit c08d251f3cc9b1a5b69a268f952d64f990366835 $ ***************************************************************************** * Copyright (C) 2002 The Regents of the University of California. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). * Written by Mark Grondona * UCRL-CODE-2002-040. * * This file is part of SLURM, a resource management program. * For details, see . * * SLURM 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. * * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along * with SLURM; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. \*****************************************************************************/ #ifdef HAVE_CONFIG_H # include "config.h" # if HAVE_STRING_H # include # endif # if HAVE_PTHREAD_H # include # endif #else /* !HAVE_CONFIG_H */ # include # include #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include #include "hostlist.h" /* * lsd_fatal_error : fatal error macro */ #ifdef WITH_LSD_FATAL_ERROR_FUNC # undef lsd_fatal_error extern void lsd_fatal_error(char *file, int line, char *mesg); #else /* !WITH_LSD_FATAL_ERROR_FUNC */ # ifndef lsd_fatal_error # define lsd_fatal_error(file, line, mesg) \ do { \ fprintf(stderr, "ERROR: [%s:%d] %s: %s\n", \ file, line, mesg, strerror(errno)); \ } while (0) # endif /* !lsd_fatal_error */ #endif /* !WITH_LSD_FATAL_ERROR_FUNC */ /* * lsd_nomem_error */ #ifdef WITH_LSD_NOMEM_ERROR_FUNC # undef lsd_nomem_error extern void * lsd_nomem_error(char *file, int line, char *mesg); #else /* !WITH_LSD_NOMEM_ERROR_FUNC */ # ifndef lsd_nomem_error # define lsd_nomem_error(file, line, mesg) (NULL) # endif /* !lsd_nomem_error */ #endif /* !WITH_LSD_NOMEM_ERROR_FUNC */ /* * OOM helper function * Automatically call lsd_nomem_error with appropriate args * and set errno to ENOMEM */ #define out_of_memory(mesg) \ do { \ errno = ENOMEM; \ return(lsd_nomem_error(__FILE__, __LINE__, mesg)); \ } while (0) /* * Some constants and tunables: */ /* number of elements to allocate when extending the hostlist array */ #define HOSTLIST_CHUNK 16 /* max host range: anything larger will be assumed to be an error */ #define MAX_RANGE 16384 /* 16K Hosts */ /* max host suffix value */ #define MAX_HOST_SUFFIX 1<<25 /* max number of ranges that will be processed between brackets */ #define MAX_RANGES 10240 /* 10K Ranges */ /* size of internal hostname buffer (+ some slop), hostnames will probably * be truncated if longer than MAXHOSTNAMELEN */ #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif /* max size of internal hostrange buffer */ #define MAXHOSTRANGELEN 1024 /* ----[ Internal Data Structures ]---- */ /* hostname type: A convenience structure used in parsing single hostnames */ struct hostname_components { char *hostname; /* cache of initialized hostname */ char *prefix; /* hostname prefix */ unsigned long num; /* numeric suffix */ /* string representation of numeric suffix * points into `hostname' */ char *suffix; }; typedef struct hostname_components *hostname_t; /* hostrange type: A single prefix with `hi' and `lo' numeric suffix values */ struct hostrange_components { char *prefix; /* alphanumeric prefix: */ /* beginning (lo) and end (hi) of suffix range */ unsigned long lo, hi; /* width of numeric output format * (pad with zeros up to this width) */ int width; /* If singlehost is 1, `lo' and `hi' are invalid */ unsigned singlehost:1; }; typedef struct hostrange_components *hostrange_t; /* The hostlist type: An array based list of hostrange_t's */ struct hostlist { #ifndef NDEBUG #define HOSTLIST_MAGIC 57005 int magic; #endif #if WITH_PTHREADS pthread_mutex_t mutex; #endif /* WITH_PTHREADS */ /* current number of elements available in array */ int size; /* current number of ranges stored in array */ int nranges; /* current number of hosts stored in hostlist */ int nhosts; /* pointer to hostrange array */ hostrange_t *hr; /* list of iterators */ struct hostlist_iterator *ilist; }; /* a hostset is a wrapper around a hostlist */ struct hostset { hostlist_t hl; }; struct hostlist_iterator { #ifndef NDEBUG int magic; #endif /* hostlist we are traversing */ hostlist_t hl; /* current index of iterator in hl->hr[] */ int idx; /* current hostrange object in list hl, i.e. hl->hr[idx] */ hostrange_t hr; /* current depth we've traversed into range hr */ int depth; /* next ptr for lists of iterators */ struct hostlist_iterator *next; }; /* ---- ---- */ /* ------[ static function prototypes ]------ */ static void _error(char *file, int line, char *mesg, ...); static char * _next_tok(char *, char **); static int _zero_padded(unsigned long, int); static int _width_equiv(unsigned long, int *, unsigned long, int *); static int host_prefix_end(const char *); static hostname_t hostname_create(const char *); static void hostname_destroy(hostname_t); static int hostname_suffix_is_valid(hostname_t); static int hostname_suffix_width(hostname_t); static hostrange_t hostrange_new(void); static hostrange_t hostrange_create_single(const char *); static hostrange_t hostrange_create(char *, unsigned long, unsigned long, int); static unsigned long hostrange_count(hostrange_t); static hostrange_t hostrange_copy(hostrange_t); static void hostrange_destroy(hostrange_t); static hostrange_t hostrange_delete_host(hostrange_t, unsigned long); static int hostrange_cmp(hostrange_t, hostrange_t); static int hostrange_prefix_cmp(hostrange_t, hostrange_t); static int hostrange_within_range(hostrange_t, hostrange_t); static int hostrange_width_combine(hostrange_t, hostrange_t); static int hostrange_empty(hostrange_t); static char * hostrange_pop(hostrange_t); static char * hostrange_shift(hostrange_t); static int hostrange_join(hostrange_t, hostrange_t); static hostrange_t hostrange_intersect(hostrange_t, hostrange_t); static int hostrange_hn_within(hostrange_t, hostname_t); static size_t hostrange_to_string(hostrange_t hr, size_t, char *, char *); static size_t hostrange_numstr(hostrange_t, size_t, char *); static hostlist_t hostlist_new(void); static hostlist_t _hostlist_create_bracketed(const char *, char *, char *); static int hostlist_resize(hostlist_t, size_t); static int hostlist_expand(hostlist_t); static int hostlist_push_range(hostlist_t, hostrange_t); static int hostlist_push_hr(hostlist_t, char *, unsigned long, unsigned long, int); static int hostlist_insert_range(hostlist_t, hostrange_t, int); static void hostlist_delete_range(hostlist_t, int n); static void hostlist_coalesce(hostlist_t hl); static void hostlist_collapse(hostlist_t hl); static hostlist_t _hostlist_create(const char *, char *, char *); static void hostlist_shift_iterators(hostlist_t, int, int, int); static int _attempt_range_join(hostlist_t, int); static int _is_bracket_needed(hostlist_t, int); static hostlist_iterator_t hostlist_iterator_new(void); static void _iterator_advance(hostlist_iterator_t); static void _iterator_advance_range(hostlist_iterator_t); static int hostset_find_host(hostset_t, const char *); /* ------[ macros ]------ */ #ifdef WITH_PTHREADS # define mutex_init(mutex) \ do { \ int e = pthread_mutex_init(mutex, NULL); \ if (e) { \ errno = e; \ lsd_fatal_error(__FILE__, __LINE__, "hostlist mutex init:"); \ abort(); \ } \ } while (0) # define mutex_lock(mutex) \ do { \ int e = pthread_mutex_lock(mutex); \ if (e) { \ errno = e; \ lsd_fatal_error(__FILE__, __LINE__, "hostlist mutex lock:"); \ abort(); \ } \ } while (0) # define mutex_unlock(mutex) \ do { \ int e = pthread_mutex_unlock(mutex); \ if (e) { \ errno = e; \ lsd_fatal_error(__FILE__, __LINE__, "hostlist mutex unlock:"); \ abort(); \ } \ } while (0) # define mutex_destroy(mutex) \ do { \ int e = pthread_mutex_destroy(mutex); \ if (e) { \ errno = e; \ lsd_fatal_error(__FILE__, __LINE__, "hostlist mutex destroy:"); \ abort(); \ } \ } while (0) #else /* !WITH_PTHREADS */ # define mutex_init(mutex) # define mutex_lock(mutex) # define mutex_unlock(mutex) # define mutex_destroy(mutex) #endif /* WITH_PTHREADS */ #define LOCK_HOSTLIST(_hl) \ do { \ assert(_hl != NULL); \ mutex_lock(&(_hl)->mutex); \ assert((_hl)->magic == HOSTLIST_MAGIC); \ } while (0) #define UNLOCK_HOSTLIST(_hl) \ do { \ mutex_unlock(&(_hl)->mutex); \ } while (0) #define seterrno_ret(_errno, _rc) \ do { \ errno = _errno; \ return _rc; \ } while (0) /* ------[ Function Definitions ]------ */ /* ----[ general utility functions ]---- */ /* * Varargs capable error reporting via lsd_fatal_error() */ static void _error(char *file, int line, char *msg, ...) { va_list ap; char buf[1024]; int len = 0; va_start(ap, msg); len = vsnprintf(buf, 1024, msg, ap); if ((len < 0) || (len > 1024)) buf[1023] = '\0'; lsd_fatal_error(file, line, buf); va_end(ap); return; } /* * Helper function for host list string parsing routines * Returns a pointer to the next token; additionally advance *str * to the next separator. * * next_tok was taken directly from pdsh courtesy of Jim Garlick. * (with modifications to support bracketed hostlists, i.e.: * xxx[xx,xx,xx] is a single token) * * _next_tok now handles multiple brackets within the same token, * e.g. node[01-30]-[1-2,6]. */ static char * _next_tok(char *sep, char **str) { char *tok; int level = 0; /* push str past any leading separators */ while (**str != '\0' && strchr(sep, **str)) (*str)++; if (**str == '\0') return NULL; /* assign token ptr */ tok = *str; while ( **str != '\0' && (level != 0 || strchr(sep, **str) == NULL) ) { if ( **str == '[' ) level++; else if ( **str == ']' ) level--; (*str)++; } /* nullify consecutive separators and push str beyond them */ while (**str != '\0' && strchr(sep, **str) != NULL) *(*str)++ = '\0'; return tok; } /* return the number of zeros needed to pad "num" to "width" */ static int _zero_padded(unsigned long num, int width) { int n = 1; while (num /= 10L) n++; return width > n ? width - n : 0; } /* test whether two format `width' parameters are "equivalent" * The width arguments "wn" and "wm" for integers "n" and "m" * are equivalent if: * * o wn == wm OR * * o applying the same format width (either wn or wm) to both of * 'n' and 'm' will not change the zero padding of *either* 'm' nor 'n'. * * If this function returns 1 (or true), the appropriate width value * (either 'wm' or 'wn') will have been adjusted such that both format * widths are equivalent. */ static int _width_equiv(unsigned long n, int *wn, unsigned long m, int *wm) { int npad, nmpad, mpad, mnpad; if (wn == wm) return 1; npad = _zero_padded(n, *wn); nmpad = _zero_padded(n, *wm); mpad = _zero_padded(m, *wm); mnpad = _zero_padded(m, *wn); if (npad != nmpad && mpad != mnpad) return 0; if (npad != nmpad) { if (mpad == mnpad) { *wm = *wn; return 1; } else return 0; } else { /* mpad != mnpad */ if (npad == nmpad) { *wn = *wm; return 1; } else return 0; } /* not reached */ } /* ----[ hostname_t functions ]---- */ /* * return the location of the last char in the hostname prefix */ static int host_prefix_end(const char *hostname) { int idx = strlen(hostname) - 1; while (idx >= 0 && isdigit((char) hostname[idx])) idx--; return idx; } static hostname_t hostname_create_with_suffix (const char *hostname, int idx) { hostname_t hn = NULL; char *p = "\0"; assert(hostname != NULL); if (!(hn = (hostname_t) malloc(sizeof(*hn)))) out_of_memory("hostname create"); if (!(hn->hostname = strdup(hostname))) { free(hn); out_of_memory("hostname create"); } hn->num = 0; hn->prefix = NULL; hn->suffix = NULL; if (idx == strlen(hostname) - 1) { if ((hn->prefix = strdup(hostname)) == NULL) { hostname_destroy(hn); out_of_memory("hostname prefix create"); } return hn; } hn->suffix = hn->hostname + idx + 1; hn->num = strtoul(hn->suffix, &p, 10); if ((*p == '\0') && (hn->num <= MAX_HOST_SUFFIX)) { if (!(hn->prefix = malloc((idx + 2) * sizeof(char)))) { hostname_destroy(hn); out_of_memory("hostname prefix create"); } memcpy(hn->prefix, hostname, idx + 1); hn->prefix[idx + 1] = '\0'; } else { if (!(hn->prefix = strdup(hostname))) { hostname_destroy(hn); out_of_memory("hostname prefix create"); } hn->suffix = NULL; } return hn; } /* * create a hostname_t object from a string hostname */ static hostname_t hostname_create(const char *hostname) { int idx = host_prefix_end (hostname); return hostname_create_with_suffix (hostname, idx); } /* free a hostname object */ static void hostname_destroy(hostname_t hn) { if (hn == NULL) return; hn->suffix = NULL; if (hn->hostname) free(hn->hostname); if (hn->prefix) free(hn->prefix); free(hn); } /* return true if the hostname has a valid numeric suffix */ static int hostname_suffix_is_valid(hostname_t hn) { return hn->suffix != NULL; } /* return the width (in characters) of the numeric part of the hostname */ static int hostname_suffix_width(hostname_t hn) { assert(hn->suffix != NULL); return (int) strlen(hn->suffix); } /* ----[ hostrange_t functions ]---- */ /* allocate a new hostrange object */ static hostrange_t hostrange_new(void) { hostrange_t new = (hostrange_t) malloc(sizeof(*new)); if (!new) out_of_memory("hostrange create"); return new; } /* Create a hostrange_t containing a single host without a valid suffix * hr->prefix will represent the entire hostname. */ static hostrange_t hostrange_create_single(const char *prefix) { hostrange_t new; assert(prefix != NULL); if ((new = hostrange_new()) == NULL) goto error1; if ((new->prefix = strdup(prefix)) == NULL) goto error2; new->singlehost = 1; new->lo = 0L; new->hi = 0L; new->width = 0; return new; error2: free(new); error1: out_of_memory("hostrange create single"); } /* Create a hostrange object with a prefix, hi, lo, and format width */ static hostrange_t hostrange_create(char *prefix, unsigned long lo, unsigned long hi, int width) { hostrange_t new; assert(prefix != NULL); if ((new = hostrange_new()) == NULL) goto error1; if ((new->prefix = strdup(prefix)) == NULL) goto error2; new->lo = lo; new->hi = hi; new->width = width; new->singlehost = 0; return new; error2: free(new); error1: out_of_memory("hostrange create"); } /* Return the number of hosts stored in the hostrange object */ static unsigned long hostrange_count(hostrange_t hr) { assert(hr != NULL); if (hr->singlehost) return 1; else return hr->hi - hr->lo + 1; } /* Copy a hostrange object */ static hostrange_t hostrange_copy(hostrange_t hr) { assert(hr != NULL); if (hr->singlehost) return hostrange_create_single(hr->prefix); else return hostrange_create(hr->prefix, hr->lo, hr->hi, hr->width); } /* free memory allocated by the hostrange object */ static void hostrange_destroy(hostrange_t hr) { if (hr == NULL) return; if (hr->prefix) free(hr->prefix); free(hr); } /* hostrange_delete_host() deletes a specific host from the range. * If the range is split into two, the greater range is returned, * and `hi' of the lesser range is adjusted accordingly. If the * highest or lowest host is deleted from a range, NULL is returned * and the hostrange hr is adjusted properly. */ static hostrange_t hostrange_delete_host(hostrange_t hr, unsigned long n) { hostrange_t new = NULL; assert(hr != NULL); assert(n >= hr->lo && n <= hr->hi); if (n == hr->lo) hr->lo++; else if (n == hr->hi) hr->hi--; else { if (!(new = hostrange_copy(hr))) out_of_memory("hostrange copy"); hr->hi = n - 1; new->lo = n + 1; } return new; } /* hostrange_cmp() is used to sort hostrange objects. It will * sort based on the following (in order): * o result of strcmp on prefixes * o if widths are compatible, then: * sort based on lowest suffix in range * else * sort based on width */ static int hostrange_cmp(hostrange_t h1, hostrange_t h2) { int retval; assert(h1 != NULL); assert(h2 != NULL); if ((retval = hostrange_prefix_cmp(h1, h2)) == 0) retval = hostrange_width_combine(h1, h2) ? h1->lo - h2->lo : h1->width - h2->width; return retval; } /* compare the prefixes of two hostrange objects. * returns: * < 0 if h1 prefix is less than h2 OR h1 == NULL. * * 0 if h1's prefix and h2's prefix match, * UNLESS, either h1 or h2 (NOT both) do not have a valid suffix. * * > 0 if h1's prefix is greater than h2's OR h2 == NULL. */ static int hostrange_prefix_cmp(hostrange_t h1, hostrange_t h2) { int retval; if (h1 == NULL) return 1; if (h2 == NULL) return -1; retval = strcmp(h1->prefix, h2->prefix); return retval == 0 ? h2->singlehost - h1->singlehost : retval; } /* returns true if h1 and h2 would be included in the same bracketed hostlist. * h1 and h2 will be in the same bracketed list iff: * * 1. h1 and h2 have same prefix * 2. neither h1 nor h2 are singlet hosts (i.e. invalid suffix) * * (XXX: Should incompatible widths be placed in the same bracketed list? * There's no good reason not to, except maybe aesthetics) */ static int hostrange_within_range(hostrange_t h1, hostrange_t h2) { if (hostrange_prefix_cmp(h1, h2) == 0) return h1->singlehost || h2->singlehost ? 0 : 1; else return 0; } /* compare two hostrange objects to determine if they are width * compatible, returns: * 1 if widths can safely be combined * 0 if widths cannot be safely combined */ static int hostrange_width_combine(hostrange_t h0, hostrange_t h1) { assert(h0 != NULL); assert(h1 != NULL); return _width_equiv(h0->lo, &h0->width, h1->lo, &h1->width); } /* Return true if hostrange hr contains no hosts, i.e. hi < lo */ static int hostrange_empty(hostrange_t hr) { assert(hr != NULL); return ((hr->hi < hr->lo) || (hr->hi == (unsigned long) -1)); } /* return the string representation of the last host in hostrange hr * and remove that host from the range (i.e. decrement hi if possible) * * Returns NULL if malloc fails OR there are no more hosts left */ static char *hostrange_pop(hostrange_t hr) { size_t size = 0; char *host = NULL; assert(hr != NULL); if (hr->singlehost) { hr->lo++; /* effectively set count == 0 */ host = strdup(hr->prefix); } else if (hostrange_count(hr) > 0) { size = strlen(hr->prefix) + hr->width + 16; if (!(host = (char *) malloc(size * sizeof(char)))) out_of_memory("hostrange pop"); snprintf(host, size, "%s%0*lu", hr->prefix, hr->width, hr->hi--); } return host; } /* Same as hostrange_pop(), but remove host from start of range */ static char *hostrange_shift(hostrange_t hr) { size_t size = 0; char *host = NULL; assert(hr != NULL); if (hr->singlehost) { hr->lo++; if (!(host = strdup(hr->prefix))) out_of_memory("hostrange shift"); } else if (hostrange_count(hr) > 0) { size = strlen(hr->prefix) + hr->width + 16; if (!(host = (char *) malloc(size * sizeof(char)))) out_of_memory("hostrange shift"); snprintf(host, size, "%s%0*lu", hr->prefix, hr->width, hr->lo++); } return host; } /* join two hostrange objects. * * returns: * * -1 if ranges do not overlap (including incompatible zero padding) * 0 if ranges join perfectly * >0 number of hosts that were duplicated in h1 and h2 * * h2 will be coalesced into h1 if rc >= 0 * * it is assumed that h1->lo <= h2->lo, i.e. hr1 <= hr2 * */ static int hostrange_join(hostrange_t h1, hostrange_t h2) { int duplicated = -1; assert(h1 != NULL); assert(h2 != NULL); assert(hostrange_cmp(h1, h2) <= 0); if (hostrange_prefix_cmp(h1, h2) == 0 && hostrange_width_combine(h1, h2)) { if (h1->singlehost && h2->singlehost) { /* matching singlets */ duplicated = 1; } else if (h1->hi == h2->lo - 1) { /* perfect join */ h1->hi = h2->hi; duplicated = 0; } else if (h1->hi >= h2->lo) { /* some duplication */ if (h1->hi < h2->hi) { duplicated = h1->hi - h2->lo + 1; h1->hi = h2->hi; } else duplicated = hostrange_count(h2); } } return duplicated; } /* hostrange intersect returns the intersection (common hosts) * of hostrange objects h1 and h2. If there is no intersection, * NULL is returned. * * It is assumed that h1 <= h2 (i.e. h1->lo <= h2->lo) */ static hostrange_t hostrange_intersect(hostrange_t h1, hostrange_t h2) { hostrange_t new = NULL; assert(h1 != NULL); assert(h2 != NULL); if (h1->singlehost || h2->singlehost) return NULL; assert(hostrange_cmp(h1, h2) <= 0); if ((hostrange_prefix_cmp(h1, h2) == 0) && (h1->hi > h2->lo) && (hostrange_width_combine(h1, h2))) { if (!(new = hostrange_copy(h1))) return NULL; new->lo = h2->lo; new->hi = h2->hi < h1->hi ? h2->hi : h1->hi; } return new; } /* return offset of hn if it is in the hostlist or * -1 if not. */ static int hostrange_hn_within(hostrange_t hr, hostname_t hn) { int len_hr; int len_hn; int width; if (hr->singlehost) { /* * If the current hostrange [hr] is a `singlehost' (no valid * numeric suffix (lo and hi)), then the hostrange [hr] * stores just one host with name == hr->prefix. * * Thus the full hostname in [hn] must match hr->prefix, in * which case we return true. Otherwise, there is no * possibility that [hn] matches [hr]. */ if (strcmp (hn->hostname, hr->prefix) == 0) return 0; else return -1; } /* * Now we know [hr] is not a "singlehost", so hostname * better have a valid numeric suffix, or there is no * way we can match */ if (!hostname_suffix_is_valid (hn)) return -1; len_hn = strlen (hn->prefix); /* * If hostrange and hostname prefixes don't match to at least * the length of the hostname object (which will have the min * possible prefix length), then there is no way the hostname * falls within the range [hr]. */ if (strncmp (hr->prefix, hn->prefix, len_hn) != 0) return -1; /* * Now we know hostrange and hostname prefixes match up to the * length of the hostname prefix. If the hostrange and hostname * prefix lengths do not match (specifically if the hostname prefix * length is less than the hostrange prefix length) and the * hostrange prefix contains trailing digits, then it might be * the case that the hostrange was created by forcing the prefix * to contain digits a la f00[1-2]. So we try adjusting the * hostname with the longer prefix and calling this function * again with the new hostname. (Yes, this is ugly, sorry) */ len_hr = strlen (hr->prefix); width = hostname_suffix_width (hn); if ((len_hn < len_hr) && (width > 1) && (isdigit (hr->prefix [len_hr - 1])) && (hr->prefix [len_hn] == hn->suffix[0]) ) { int rc; /* * Create new hostname object with its prefix offset by one */ hostname_t h = hostname_create_with_suffix (hn->hostname, len_hn); /* * Recursive call :-o */ rc = hostrange_hn_within (hr, h); hostname_destroy (h); return rc; } /* * Finally, check whether [hn], with a valid numeric suffix, * falls within the range of [hr] if [hn] and [hr] prefix are * identical. */ if ((len_hr == len_hn) && (strcmp (hn->prefix, hr->prefix) == 0) && (hn->num <= hr->hi) && (hn->num >= hr->lo)) { int width = hostname_suffix_width (hn); if (!_width_equiv(hr->lo, &hr->width, hn->num, &width)) return -1; return (hn->num - hr->lo); } return -1; } /* copy a string representation of the hostrange hr into buffer buf, * writing at most n chars including NUL termination */ static size_t hostrange_to_string(hostrange_t hr, size_t n, char *buf, char *separator) { unsigned long i; int truncated = 0; int len = 0; char sep = separator == NULL ? ',' : separator[0]; if (n == 0) return 0; if (hr->singlehost) return snprintf(buf, n, "%s", hr->prefix); for (i = hr->lo; i <= hr->hi; i++) { size_t m = (n - len) <= n ? n - len : 0; /* check for < 0 */ int ret = snprintf(buf + len, m, "%s%0*lu", hr->prefix, hr->width, i); if (ret < 0 || ret >= m) { len = n; truncated = 1; break; } len+=ret; buf[len++] = sep; } if (truncated) { buf[n-1] = '\0'; return -1; } else { /* back up over final separator */ buf[--len] = '\0'; return len; } } /* Place the string representation of the numeric part of hostrange into buf * writing at most n chars including NUL termination. */ static size_t hostrange_numstr(hostrange_t hr, size_t n, char *buf) { int len = 0; assert(buf != NULL); if (hr->singlehost || n == 0) return 0; len = snprintf(buf, n, "%0*lu", hr->width, hr->lo); if ((len >= 0) && (len < n) && (hr->lo < hr->hi)) { int len2 = snprintf(buf+len, n-len, "-%0*lu", hr->width, hr->hi); if (len2 < 0) len = -1; else len += len2; } return len; } /* ----[ hostlist functions ]---- */ /* Create a new hostlist object. * Returns an empty hostlist, or NULL if memory allocation fails. */ static hostlist_t hostlist_new(void) { int i; hostlist_t new = (hostlist_t) malloc(sizeof(*new)); if (!new) goto fail1; assert((new->magic = HOSTLIST_MAGIC)); mutex_init(&new->mutex); new->hr = (hostrange_t *) malloc(HOSTLIST_CHUNK * sizeof(hostrange_t)); if (!new->hr) goto fail2; /* set entries in hostrange array to NULL */ for (i = 0; i < HOSTLIST_CHUNK; i++) new->hr[i] = NULL; new->size = HOSTLIST_CHUNK; new->nranges = 0; new->nhosts = 0; new->ilist = NULL; return new; fail2: free(new); fail1: out_of_memory("hostlist_create"); } /* Resize the internal array used to store the list of hostrange objects. * * returns 1 for a successful resize, * 0 if call to _realloc fails * * It is assumed that the caller has the hostlist hl locked */ static int hostlist_resize(hostlist_t hl, size_t newsize) { int i; size_t oldsize; assert(hl != NULL); assert((hl->magic == HOSTLIST_MAGIC)); oldsize = hl->size; hl->size = newsize; hl->hr = realloc((void *) hl->hr, hl->size*sizeof(hostrange_t)); if (!(hl->hr)) return 0; for (i = oldsize; i < newsize; i++) hl->hr[i] = NULL; return 1; } /* Resize hostlist by one HOSTLIST_CHUNK * Assumes that hostlist hl is locked by caller */ static int hostlist_expand(hostlist_t hl) { if (!hostlist_resize(hl, hl->size + HOSTLIST_CHUNK)) return 0; else return 1; } /* Push a hostrange object onto hostlist hl * Returns the number of hosts successfully pushed onto hl * or -1 if there was an error allocating memory */ static int hostlist_push_range(hostlist_t hl, hostrange_t hr) { hostrange_t tail; int retval; assert(hr != NULL); LOCK_HOSTLIST(hl); tail = (hl->nranges > 0) ? hl->hr[hl->nranges-1] : hl->hr[0]; if (hl->size == hl->nranges && !hostlist_expand(hl)) goto error; if (hl->nranges > 0 && hostrange_prefix_cmp(tail, hr) == 0 && tail->hi == hr->lo - 1 && hostrange_width_combine(tail, hr)) { tail->hi = hr->hi; } else { if ((hl->hr[hl->nranges++] = hostrange_copy(hr)) == NULL) goto error; } retval = hl->nhosts += hostrange_count(hr); UNLOCK_HOSTLIST(hl); return retval; error: UNLOCK_HOSTLIST(hl); return -1; } /* Same as hostlist_push_range() above, but prefix, lo, hi, and width * are passed as args */ static int hostlist_push_hr(hostlist_t hl, char *prefix, unsigned long lo, unsigned long hi, int width) { hostrange_t hr = hostrange_create(prefix, lo, hi, width); int retval = hostlist_push_range(hl, hr); hostrange_destroy(hr); return retval; } /* Insert a range object hr into position n of the hostlist hl * Assumes that hl->mutex is already held by calling process */ static int hostlist_insert_range(hostlist_t hl, hostrange_t hr, int n) { int i; hostrange_t tmp; hostlist_iterator_t hli; assert(hl != NULL); assert((hl->magic == HOSTLIST_MAGIC)); assert(hr != NULL); if (n > hl->nranges) return 0; if (hl->size == hl->nranges && !hostlist_expand(hl)) return 0; /* copy new hostrange into slot "n" in array */ tmp = hl->hr[n]; hl->hr[n] = hostrange_copy(hr); /* push remaining hostrange entries up */ for (i = n + 1; i < hl->nranges + 1; i++) { hostrange_t last = hl->hr[i]; hl->hr[i] = tmp; tmp = last; } hl->nranges++; /* adjust hostlist iterators if needed */ for (hli = hl->ilist; hli; hli = hli->next) { if (hli->idx >= n) hli->hr = hli->hl->hr[++hli->idx]; } return 1; } /* Delete the range at position n in the range array * Assumes the hostlist lock is already held. */ static void hostlist_delete_range(hostlist_t hl, int n) { int i; hostrange_t old; assert(hl != NULL); assert((hl->magic == HOSTLIST_MAGIC)); assert(n < hl->nranges && n >= 0); old = hl->hr[n]; for (i = n; i < hl->nranges - 1; i++) hl->hr[i] = hl->hr[i + 1]; hl->nranges--; hl->hr[hl->nranges] = NULL; hostlist_shift_iterators(hl, n, 0, 1); /* XXX caller responsible for adjusting nhosts */ /* hl->nhosts -= hostrange_count(old) */ hostrange_destroy(old); } #if WANT_RECKLESS_HOSTRANGE_EXPANSION /* The reckless hostrange expansion function. * See comment in hostlist.h:hostlist_create() for more info on * the different choices for hostlist notation. */ hostlist_t _hostlist_create(const char *hostlist, char *sep, char *r_op) { char *str, *orig; char *tok, *cur; int high, low, fmt = 0; char prefix[256] = ""; int pos = 0; int error = 0; char range_op = r_op[0];/* XXX support > 1 char range ops in future? */ hostlist_t new = hostlist_new(); orig = str = strdup(hostlist); /* return an empty list if an empty string was passed in */ if (str == NULL || strlen(str) == 0) goto done; /* Use hostlist_create_bracketed if we see "[" */ if (strchr(str, '[') != NULL) return _hostlist_create_bracketed(hostlist, sep, r_op); while ((tok = _next_tok(sep, &str)) != NULL) { /* save the current string for error messages */ cur = tok; high = low = 0; /* find end of alpha part * do this by finding last occurence of range_op in str */ pos = strlen(tok) - 1; if (strstr(tok, r_op) != NULL) { while (pos >= 0 && (char) tok[pos] != range_op) pos--; } /* now back up past any digits */ while (pos >= 0 && isdigit((char) tok[--pos])) {;} /* Check for valid x-y range (x must be a digit) * Reset pos if the range is not valid */ if (!isdigit((char) tok[++pos])) pos = strlen(tok) - 1; /* create prefix string * if prefix will be zero length, but prefix already exists * use the previous prefix and fmt */ if ((pos > 0) || (prefix[0] == '\0')) { memcpy(prefix, tok, (size_t) pos * sizeof(char)); prefix[pos] = '\0'; /* push pointer past prefix */ tok += pos; /* count number of digits for ouput fmt */ for (fmt = 0; isdigit(tok[fmt]); ++fmt) {;} if (fmt == 0) error = 1; } else tok += pos; /* get lower bound */ low = strtoul(tok, (char **) &tok, 10); if (*tok == range_op) { /* now get range upper bound */ /* push pointer past range op */ ++tok; /* find length of alpha part */ for (pos = 0; tok[pos] && !isdigit(tok[pos]); ++pos) {;} /* alpha part must match prefix or error * this could mean we've got something like "rtr1-a2" * so just record an error */ if (pos > 0) { if (pos != strlen(prefix) || strncmp(prefix, tok, pos) != 0) error = 1; } if (*tok != '\0') tok += pos; /* make sure we have digits to the end */ for (pos = 0; tok[pos] && isdigit((char) tok[pos]); ++pos) {;} if (pos > 0) { /* we have digits to process */ high = strtoul(tok, (char **) &tok, 10); } else { /* bad boy, no digits */ error = 1; } if ((low > high) || (high - low > MAX_RANGE)) error = 1; } else { /* single value */ high = 0; /* special case, ugh. */ } /* error if: * 1. we are not at end of string * 2. upper bound equals lower bound */ if (*tok != '\0' || high == low) error = 1; if (error) { /* assume this is not a range on any error */ hostlist_push_host(new, cur); } else { if (high < low) high = low; hostlist_push_hr(new, prefix, low, high, fmt); } error = 0; } done: free(orig); return new; } #else /* !WANT_RECKLESS_HOSTRANGE_EXPANSION */ hostlist_t _hostlist_create(const char *hostlist, char *sep, char *r_op) { return _hostlist_create_bracketed(hostlist, sep, r_op); } #endif /* WANT_RECKLESS_HOSTRANGE_EXPANSION */ struct _range { unsigned long lo, hi; int width; }; /* Grab a single range from str * returns 1 if str contained a valid number or range, * 0 if conversion of str to a range failed. */ static int _parse_single_range(const char *str, struct _range *range) { char *p, *q; char *orig = strdup(str); if (!orig) seterrno_ret(ENOMEM, 0); if ((p = strchr(str, '-'))) { *p++ = '\0'; if (*p == '-') /* do NOT allow negative numbers */ goto error; } range->lo = strtoul(str, &q, 10); if (q == str) goto error; range->hi = (p && *p) ? strtoul(p, &q, 10) : range->lo; if (q == p || *q != '\0') goto error; if (range->lo > range->hi) goto error; if (range->hi - range->lo + 1 > MAX_RANGE ) { _error(__FILE__, __LINE__, "Too many hosts in range `%s'", orig); free(orig); seterrno_ret(ERANGE, 0); } free(orig); range->width = strlen(str); return 1; error: _error(__FILE__, __LINE__, "Invalid range: `%s'", orig); free(orig); seterrno_ret(EINVAL, 0); } /* * Convert 'str' containing comma separated digits and ranges into an array * of struct _range types (max 'len' elements). * * Return number of ranges created, or -1 on error. */ static int _parse_range_list(char *str, struct _range *ranges, int len) { char *p; int count = 0; while (str) { if (count == len) return -1; if ((p = strchr(str, ','))) *p++ = '\0'; if (!_parse_single_range(str, &ranges[count++])) return -1; str = p; } return count; } static void _push_range_list(hostlist_t hl, char *pfx, struct _range *rng, int n) { int i; for (i = 0; i < n; i++) { hostlist_push_hr(hl, pfx, rng->lo, rng->hi, rng->width); rng++; } } static void _push_range_list_with_suffix(hostlist_t hl, char *pfx, char *sfx, struct _range *rng, int n) { int i; unsigned long j; for (i = 0; i < n; i++) { for (j = rng->lo; j <= rng->hi; j++) { char host[4096]; hostrange_t hr; snprintf (host, 4096, "%s%0*lu%s", pfx, rng->width, j, sfx); hr = hostrange_create_single (host); hostlist_push_range (hl, hr); /* * hr is copied in hostlist_push_range. Need to free here. */ hostrange_destroy (hr); } rng++; } } /* * Create a hostlist from a string with brackets '[' ']' to aid * detection of ranges and compressed lists */ static hostlist_t _hostlist_create_bracketed(const char *hostlist, char *sep, char *r_op) { hostlist_t new = hostlist_new(); struct _range ranges[MAX_RANGES]; int nr, err; char *p, *tok, *str, *orig; char cur_tok[1024]; if (hostlist == NULL) return new; if (!(orig = str = strdup(hostlist))) { hostlist_destroy(new); return NULL; } while ((tok = _next_tok(sep, &str)) != NULL) { strncpy(cur_tok, tok, sizeof (cur_tok) - 1); if ((p = strchr(tok, '[')) != NULL) { char *q, *prefix = tok; *p++ = '\0'; if ((q = strchr(p, ']'))) { *q = '\0'; nr = _parse_range_list(p, ranges, MAX_RANGES); if (nr < 0) goto error; if (*(++q) != '\0') _push_range_list_with_suffix (new, prefix, q, ranges, nr); else _push_range_list(new, prefix, ranges, nr); } else /* Error: brackets must be balanced */ goto error_unmatched; } else if (strchr(tok, ']')) /* Error: brackets must be balanced */ goto error_unmatched; else /* Ok: No brackets found, single host */ hostlist_push_host(new, cur_tok); } free(orig); return new; error_unmatched: errno = EINVAL; error: err = errno; hostlist_destroy(new); free(orig); seterrno_ret(err, NULL); } hostlist_t hostlist_create(const char *str) { return _hostlist_create(str, "\t, ", "-"); } hostlist_t hostlist_copy(const hostlist_t hl) { int i; hostlist_t new; if (hl == NULL) return NULL; LOCK_HOSTLIST(hl); if (!(new = hostlist_new())) goto done; new->nranges = hl->nranges; new->nhosts = hl->nhosts; if (new->nranges > new->size) hostlist_resize(new, new->nranges); for (i = 0; i < hl->nranges; i++) new->hr[i] = hostrange_copy(hl->hr[i]); done: UNLOCK_HOSTLIST(hl); return new; } void hostlist_destroy(hostlist_t hl) { int i; if (hl == NULL) return; LOCK_HOSTLIST(hl); while (hl->ilist) { mutex_unlock(&hl->mutex); hostlist_iterator_destroy(hl->ilist); mutex_lock(&hl->mutex); } for (i = 0; i < hl->nranges; i++) hostrange_destroy(hl->hr[i]); free(hl->hr); assert((hl->magic = 0x1)); UNLOCK_HOSTLIST(hl); mutex_destroy(&hl->mutex); free(hl); } int hostlist_push(hostlist_t hl, const char *hosts) { hostlist_t new; int retval; if (hosts == NULL) return 0; new = hostlist_create(hosts); if (!new) return 0; mutex_lock(&new->mutex); retval = new->nhosts; mutex_unlock(&new->mutex); hostlist_push_list(hl, new); hostlist_destroy(new); return retval; } int hostlist_push_host(hostlist_t hl, const char *str) { hostrange_t hr; hostname_t hn; if (str == NULL) return 0; hn = hostname_create(str); if (hostname_suffix_is_valid(hn)) { hr = hostrange_create(hn->prefix, hn->num, hn->num, hostname_suffix_width(hn)); } else hr = hostrange_create_single(str); hostlist_push_range(hl, hr); hostrange_destroy(hr); hostname_destroy(hn); return 1; } int hostlist_push_list(hostlist_t h1, hostlist_t h2) { int i, n = 0; if (h2 == NULL) return 0; LOCK_HOSTLIST(h2); for (i = 0; i < h2->nranges; i++) n += hostlist_push_range(h1, h2->hr[i]); UNLOCK_HOSTLIST(h2); return n; } char *hostlist_pop(hostlist_t hl) { char *host = NULL; LOCK_HOSTLIST(hl); if (hl->nhosts > 0) { hostrange_t hr = hl->hr[hl->nranges - 1]; host = hostrange_pop(hr); hl->nhosts--; if (hostrange_empty(hr)) { hostrange_destroy(hl->hr[--hl->nranges]); hl->hr[hl->nranges] = NULL; } } UNLOCK_HOSTLIST(hl); return host; } /* find all iterators affected by a shift (or deletion) at * hl->hr[idx], depth, with the deletion of n ranges */ static void hostlist_shift_iterators(hostlist_t hl, int idx, int depth, int n) { hostlist_iterator_t i; for (i = hl->ilist; i; i = i->next) { if (n == 0) { if (i->idx == idx && i->depth >= depth) i->depth = i->depth > -1 ? i->depth - 1 : -1; } else { if (i->idx >= idx) { if ((i->idx -= n) >= 0) i->hr = i->hl->hr[i->idx]; else hostlist_iterator_reset(i); } } } } char *hostlist_shift(hostlist_t hl) { char *host = NULL; LOCK_HOSTLIST(hl); if (hl->nhosts > 0) { hostrange_t hr = hl->hr[0]; host = hostrange_shift(hr); hl->nhosts--; if (hostrange_empty(hr)) { hostlist_delete_range(hl, 0); /* hl->nranges--; */ } else hostlist_shift_iterators(hl, 0, 0, 0); } UNLOCK_HOSTLIST(hl); return host; } char *hostlist_pop_range(hostlist_t hl) { int i; char buf[MAXHOSTRANGELEN + 1]; hostlist_t hltmp; hostrange_t tail; LOCK_HOSTLIST(hl); if (hl->nranges < 1 || !(hltmp = hostlist_new())) { UNLOCK_HOSTLIST(hl); return NULL; } i = hl->nranges - 2; tail = hl->hr[hl->nranges - 1]; while (i >= 0 && hostrange_within_range(tail, hl->hr[i])) i--; for (i++; i < hl->nranges; i++) { hostlist_push_range(hltmp, hl->hr[i]); hostrange_destroy(hl->hr[i]); hl->hr[i] = NULL; } hl->nhosts -= hltmp->nhosts; hl->nranges -= hltmp->nranges; UNLOCK_HOSTLIST(hl); hostlist_ranged_string(hltmp, MAXHOSTRANGELEN, buf); hostlist_destroy(hltmp); return strdup(buf); } char *hostlist_shift_range(hostlist_t hl) { int i; char buf[1024]; hostlist_t hltmp = hostlist_new(); if (!hltmp) return NULL; LOCK_HOSTLIST(hl); if (hl->nranges == 0) { hostlist_destroy(hltmp); UNLOCK_HOSTLIST(hl); return NULL; } i = 0; do { hostlist_push_range(hltmp, hl->hr[i]); hostrange_destroy(hl->hr[i]); } while ( (++i < hl->nranges) && hostrange_within_range(hltmp->hr[0], hl->hr[i]) ); hostlist_shift_iterators(hl, i, 0, hltmp->nranges); /* shift rest of ranges back in hl */ for (; i < hl->nranges; i++) { hl->hr[i - hltmp->nranges] = hl->hr[i]; hl->hr[i] = NULL; } hl->nhosts -= hltmp->nhosts; hl->nranges -= hltmp->nranges; UNLOCK_HOSTLIST(hl); hostlist_ranged_string(hltmp, 1024, buf); hostlist_destroy(hltmp); return strdup(buf); } /* XXX: Note: efficiency improvements needed */ int hostlist_delete(hostlist_t hl, const char *hosts) { int n = 0; char *hostname = NULL; hostlist_t hltmp; if (!(hltmp = hostlist_create(hosts))) seterrno_ret(EINVAL, 0); while ((hostname = hostlist_pop(hltmp)) != NULL) { n += hostlist_delete_host(hl, hostname); free(hostname); } hostlist_destroy(hltmp); return n; } /* XXX watch out! poor implementation follows! (fix it at some point) */ int hostlist_delete_host(hostlist_t hl, const char *hostname) { int n = hostlist_find(hl, hostname); if (n >= 0) hostlist_delete_nth(hl, n); return n >= 0 ? 1 : 0; } static char * _hostrange_string(hostrange_t hr, int depth) { char buf[MAXHOSTNAMELEN + 16]; int len = snprintf(buf, MAXHOSTNAMELEN + 15, "%s", hr->prefix); if (!hr->singlehost) snprintf(buf+len, MAXHOSTNAMELEN+15 - len, "%0*lu", hr->width, hr->lo + depth); return strdup(buf); } char * hostlist_nth(hostlist_t hl, int n) { char *host = NULL; int i, count; LOCK_HOSTLIST(hl); count = 0; for (i = 0; i < hl->nranges; i++) { int num_in_range = hostrange_count(hl->hr[i]); if (n <= (num_in_range - 1 + count)) { host = _hostrange_string(hl->hr[i], n - count); break; } else count += num_in_range; } UNLOCK_HOSTLIST(hl); return host; } int hostlist_delete_nth(hostlist_t hl, int n) { int i, count; LOCK_HOSTLIST(hl); assert(n >= 0 && n <= hl->nhosts); count = 0; for (i = 0; i < hl->nranges; i++) { int num_in_range = hostrange_count(hl->hr[i]); hostrange_t hr = hl->hr[i]; if (n <= (num_in_range - 1 + count)) { unsigned long num = hr->lo + n - count; hostrange_t new; if (hr->singlehost) { /* this wasn't a range */ hostlist_delete_range(hl, i); } else if ((new = hostrange_delete_host(hr, num))) { hostlist_insert_range(hl, new, i + 1); hostrange_destroy(new); } else if (hostrange_empty(hr)) hostlist_delete_range(hl, i); goto done; } else count += num_in_range; } done: hl->nhosts--; UNLOCK_HOSTLIST(hl); return 1; } int hostlist_count(hostlist_t hl) { int retval; LOCK_HOSTLIST(hl); retval = hl->nhosts; UNLOCK_HOSTLIST(hl); return retval; } int hostlist_find(hostlist_t hl, const char *hostname) { int i, count, ret = -1; hostname_t hn; if (!hostname) return -1; hn = hostname_create(hostname); LOCK_HOSTLIST(hl); for (i = 0, count = 0; i < hl->nranges; i++) { int offset = hostrange_hn_within(hl->hr[i], hn); if (offset >= 0) { ret = count + offset; break; } else count += hostrange_count(hl->hr[i]); } UNLOCK_HOSTLIST(hl); hostname_destroy(hn); return ret; } /* hostrange compare with void * arguments to allow use with * libc qsort() */ int _cmp(const void *hr1, const void *hr2) { hostrange_t *h1 = (hostrange_t *) hr1; hostrange_t *h2 = (hostrange_t *) hr2; return hostrange_cmp((hostrange_t) * h1, (hostrange_t) * h2); } void hostlist_sort(hostlist_t hl) { hostlist_iterator_t i; LOCK_HOSTLIST(hl); if (hl->nranges <= 1) { UNLOCK_HOSTLIST(hl); return; } qsort(hl->hr, hl->nranges, sizeof(hostrange_t), &_cmp); /* reset all iterators */ for (i = hl->ilist; i; i = i->next) hostlist_iterator_reset(i); UNLOCK_HOSTLIST(hl); hostlist_coalesce(hl); } /* search through hostlist for ranges that can be collapsed * does =not= delete any hosts */ static void hostlist_collapse(hostlist_t hl) { int i; LOCK_HOSTLIST(hl); for (i = hl->nranges - 1; i > 0; i--) { hostrange_t hprev = hl->hr[i - 1]; hostrange_t hnext = hl->hr[i]; if (hostrange_prefix_cmp(hprev, hnext) == 0 && hprev->hi == hnext->lo - 1 && hostrange_width_combine(hprev, hnext)) { hprev->hi = hnext->hi; hostlist_delete_range(hl, i); } } UNLOCK_HOSTLIST(hl); } /* search through hostlist (hl) for intersecting ranges * split up duplicates and coalesce ranges where possible */ static void hostlist_coalesce(hostlist_t hl) { int i, j; hostrange_t new; LOCK_HOSTLIST(hl); for (i = hl->nranges - 1; i > 0; i--) { new = hostrange_intersect(hl->hr[i - 1], hl->hr[i]); if (new) { hostrange_t hprev = hl->hr[i - 1]; hostrange_t hnext = hl->hr[i]; j = i; if (new->hi < hprev->hi) hnext->hi = hprev->hi; hprev->hi = new->lo; hnext->lo = new->hi; if (hostrange_empty(hprev)) hostlist_delete_range(hl, i); while (new->lo <= new->hi) { hostrange_t hr = hostrange_create( new->prefix, new->lo, new->lo, new->width ); if (new->lo > hprev->hi) hostlist_insert_range(hl, hr, j++); if (new->lo < hnext->lo) hostlist_insert_range(hl, hr, j++); hostrange_destroy(hr); new->lo++; } i = hl->nranges; hostrange_destroy(new); } } UNLOCK_HOSTLIST(hl); hostlist_collapse(hl); } /* attempt to join ranges at loc and loc-1 in a hostlist */ /* delete duplicates, return the number of hosts deleted */ /* assumes that the hostlist hl has been locked by caller */ /* returns -1 if no range join occurred */ static int _attempt_range_join(hostlist_t hl, int loc) { int ndup; assert(hl != NULL); assert(hl->magic == HOSTLIST_MAGIC); assert(loc > 0); assert(loc < hl->nranges); ndup = hostrange_join(hl->hr[loc - 1], hl->hr[loc]); if (ndup >= 0) { hostlist_delete_range(hl, loc); hl->nhosts -= ndup; } return ndup; } void hostlist_uniq(hostlist_t hl) { int i = 1; hostlist_iterator_t hli; LOCK_HOSTLIST(hl); if (hl->nranges <= 1) { UNLOCK_HOSTLIST(hl); return; } qsort(hl->hr, hl->nranges, sizeof(hostrange_t), &_cmp); while (i < hl->nranges) { if (_attempt_range_join(hl, i) < 0) /* No range join occurred */ i++; } /* reset all iterators */ for (hli = hl->ilist; hli; hli = hli->next) hostlist_iterator_reset(hli); UNLOCK_HOSTLIST(hl); } ssize_t hostlist_deranged_string(hostlist_t hl, size_t n, char *buf) { int i; int len = 0; int truncated = 0; LOCK_HOSTLIST(hl); for (i = 0; i < hl->nranges; i++) { size_t m = (n - len) <= n ? n - len : 0; int ret = hostrange_to_string(hl->hr[i], m, buf + len, ","); if (ret < 0 || ret > m) { len = n; truncated = 1; break; } len+=ret; buf[len++] = ','; } UNLOCK_HOSTLIST(hl); buf[len > 0 ? --len : 0] = '\0'; if (len == n) truncated = 1; return truncated ? -1 : len; } /* return true if a bracket is needed for the range at i in hostlist hl */ static int _is_bracket_needed(hostlist_t hl, int i) { hostrange_t h1 = hl->hr[i]; hostrange_t h2 = i < hl->nranges - 1 ? hl->hr[i + 1] : NULL; return hostrange_count(h1) > 1 || hostrange_within_range(h1, h2); } /* write the next bracketed hostlist, i.e. prefix[n-m,k,...] * into buf, writing at most n chars including the terminating '\0' * * leaves start pointing to one past last range object in bracketed list, * and returns the number of bytes written into buf. * * Assumes hostlist is locked. */ static int _get_bracketed_list(hostlist_t hl, int *start, const size_t n, char *buf) { hostrange_t *hr = hl->hr; int i = *start; int m, len = 0; int bracket_needed = _is_bracket_needed(hl, i); len = snprintf(buf, n, "%s", hr[i]->prefix); if ((len < 0) || (len > n)) return n; /* truncated, buffer filled */ if (bracket_needed && len < n) buf[len++] = '['; do { m = (n - len) <= n ? n - len : 0; len += hostrange_numstr(hr[i], m, buf + len); if (len >= n) break; if (bracket_needed) /* Only need commas inside brackets */ buf[len++] = ','; } while (++i < hl->nranges && hostrange_within_range(hr[i], hr[i-1])); if (bracket_needed && len < n && len > 0) { /* Add trailing bracket (change trailing "," from above to "]" */ buf[len - 1] = ']'; /* NUL terminate for safety, but do not add terminator to len */ buf[len] = '\0'; } else if (len >= n) { if (n > 0) buf[n-1] = '\0'; } else { /* If len is > 0, NUL terminate (but do not add to len) */ buf[len > 0 ? len : 0] = '\0'; } *start = i; return len; } ssize_t hostlist_ranged_string(hostlist_t hl, size_t n, char *buf) { int i = 0; int len = 0; int truncated = 0; LOCK_HOSTLIST(hl); while (i < hl->nranges && len < n) { len += _get_bracketed_list(hl, &i, n - len, buf + len); if ((len > 0) && (len < n) && (i < hl->nranges)) buf[len++] = ','; } UNLOCK_HOSTLIST(hl); /* NUL terminate */ if (len >= n) { truncated = 1; if (n > 0) buf[n-1] = '\0'; } else buf[len > 0 ? len : 0] = '\0'; return truncated ? -1 : len; } /* ----[ hostlist iterator functions ]---- */ static hostlist_iterator_t hostlist_iterator_new(void) { hostlist_iterator_t i = (hostlist_iterator_t) malloc(sizeof(*i)); if (!i) return NULL; i->hl = NULL; i->hr = NULL; i->idx = 0; i->depth = -1; i->next = i; assert((i->magic = HOSTLIST_MAGIC)); return i; } hostlist_iterator_t hostlist_iterator_create(hostlist_t hl) { hostlist_iterator_t i; if (!(i = hostlist_iterator_new())) out_of_memory("hostlist_iterator_create"); LOCK_HOSTLIST(hl); i->hl = hl; i->hr = hl->hr[0]; i->next = hl->ilist; hl->ilist = i; UNLOCK_HOSTLIST(hl); return i; } hostlist_iterator_t hostset_iterator_create(hostset_t set) { return hostlist_iterator_create(set->hl); } void hostlist_iterator_reset(hostlist_iterator_t i) { assert(i != NULL); assert(i->magic == HOSTLIST_MAGIC); i->idx = 0; i->hr = i->hl->hr[0]; i->depth = -1; return; } void hostlist_iterator_destroy(hostlist_iterator_t i) { hostlist_iterator_t *pi; if (i == NULL) return; assert(i != NULL); assert(i->magic == HOSTLIST_MAGIC); LOCK_HOSTLIST(i->hl); for (pi = &i->hl->ilist; *pi; pi = &(*pi)->next) { assert((*pi)->magic == HOSTLIST_MAGIC); if (*pi == i) { *pi = (*pi)->next; break; } } UNLOCK_HOSTLIST(i->hl); assert((i->magic = 0x1)); free(i); } static void _iterator_advance(hostlist_iterator_t i) { assert(i != NULL); assert(i->magic == HOSTLIST_MAGIC); if (i->idx > i->hl->nranges - 1) return; if (++(i->depth) > (i->hr->hi - i->hr->lo)) { i->depth = 0; if (++i->idx >= i->hl->size) { i->hr = NULL; return; } i->hr = i->hl->hr[i->idx]; } } /* advance iterator to end of current range (meaning within "[" "]") * i.e. advance iterator past all range objects that could be represented * in on bracketed hostlist. */ static void _iterator_advance_range(hostlist_iterator_t i) { int nr, j; hostrange_t *hr; assert(i != NULL); assert(i->magic == HOSTLIST_MAGIC); nr = i->hl->nranges; hr = i->hl->hr; j = i->idx; if (++i->depth > 0) { while (++j < nr && hostrange_within_range(i->hr, hr[j])) {;} i->idx = j; i->hr = i->hl->hr[i->idx]; i->depth = 0; } } char *hostlist_next(hostlist_iterator_t i) { char *buf = NULL; char suffix[16]; int len = 0; assert(i != NULL); assert(i->magic == HOSTLIST_MAGIC); LOCK_HOSTLIST(i->hl); _iterator_advance(i); if (i->idx > i->hl->nranges - 1) { UNLOCK_HOSTLIST(i->hl); return NULL; } suffix[0] = '\0'; if (!i->hr->singlehost) snprintf (suffix, 15, "%0*lu", i->hr->width, i->hr->lo + i->depth); len = strlen (i->hr->prefix) + strlen (suffix) + 1; if (!(buf = malloc (len))) out_of_memory("hostlist_next"); buf[0] = '\0'; strcat (buf, i->hr->prefix); strcat (buf, suffix); UNLOCK_HOSTLIST(i->hl); return (buf); } char *hostlist_next_range(hostlist_iterator_t i) { char buf[MAXHOSTRANGELEN + 1]; int j; assert(i != NULL); assert(i->magic == HOSTLIST_MAGIC); LOCK_HOSTLIST(i->hl); _iterator_advance_range(i); if (i->idx > i->hl->nranges - 1) { UNLOCK_HOSTLIST(i->hl); return NULL; } j = i->idx; _get_bracketed_list(i->hl, &j, MAXHOSTRANGELEN, buf); UNLOCK_HOSTLIST(i->hl); return strdup(buf); } int hostlist_remove(hostlist_iterator_t i) { hostrange_t new; assert(i != NULL); assert(i->magic == HOSTLIST_MAGIC); LOCK_HOSTLIST(i->hl); new = hostrange_delete_host(i->hr, i->hr->lo + i->depth); if (new) { hostlist_insert_range(i->hl, new, i->idx + 1); hostrange_destroy(new); i->hr = i->hl->hr[++i->idx]; i->depth = -1; } else if (hostrange_empty(i->hr)) { hostlist_delete_range(i->hl, i->idx); } else i->depth--; i->hl->nhosts--; UNLOCK_HOSTLIST(i->hl); return 1; } /* ----[ hostset functions ]---- */ hostset_t hostset_create(const char *hostlist) { hostset_t new; if (!(new = (hostset_t) malloc(sizeof(*new)))) goto error1; if (!(new->hl = hostlist_create(hostlist))) goto error2; hostlist_uniq(new->hl); return new; error2: free(new); error1: return NULL; } hostset_t hostset_copy(const hostset_t set) { hostset_t new; if (!(new = (hostset_t) malloc(sizeof(*new)))) goto error1; if (!(new->hl = hostlist_copy(set->hl))) goto error2; return new; error2: free(new); error1: return NULL; } void hostset_destroy(hostset_t set) { if (set == NULL) return; hostlist_destroy(set->hl); free(set); } /* inserts a single range object into a hostset * Assumes that the set->hl lock is already held * Updates hl->nhosts */ static int hostset_insert_range(hostset_t set, hostrange_t hr) { int i = 0; int inserted = 0; int nhosts = 0; int ndups = 0; hostlist_t hl; hl = set->hl; if (hl->size == hl->nranges && !hostlist_expand(hl)) return 0; nhosts = hostrange_count(hr); for (i = 0; i < hl->nranges; i++) { if (hostrange_cmp(hr, hl->hr[i]) <= 0) { if ((ndups = hostrange_join(hr, hl->hr[i])) >= 0) hostlist_delete_range(hl, i); else if (ndups < 0) ndups = 0; hostlist_insert_range(hl, hr, i); /* now attempt to join hr[i] and hr[i-1] */ if (i > 0) { int m; if ((m = _attempt_range_join(hl, i)) > 0) ndups += m; } hl->nhosts += nhosts - ndups; inserted = 1; break; } } if (inserted == 0) { hl->hr[hl->nranges++] = hostrange_copy(hr); hl->nhosts += nhosts; if (hl->nranges > 1) { if ((ndups = _attempt_range_join(hl, hl->nranges - 1)) <= 0) ndups = 0; } } /* * Return the number of unique hosts inserted */ return nhosts - ndups; } int hostset_insert(hostset_t set, const char *hosts) { int i, n = 0; hostlist_t hl = hostlist_create(hosts); if (!hl) return 0; hostlist_uniq(hl); LOCK_HOSTLIST(set->hl); for (i = 0; i < hl->nranges; i++) n += hostset_insert_range(set, hl->hr[i]); UNLOCK_HOSTLIST(set->hl); hostlist_destroy(hl); return n; } /* linear search through N ranges for hostname "host" * */ static int hostset_find_host(hostset_t set, const char *host) { int i; int retval = 0; hostname_t hn; LOCK_HOSTLIST(set->hl); hn = hostname_create(host); for (i = 0; i < set->hl->nranges; i++) { if (hostrange_hn_within(set->hl->hr[i], hn) >= 0) { retval = 1; goto done; } } done: UNLOCK_HOSTLIST(set->hl); hostname_destroy(hn); return retval; } int hostset_within(hostset_t set, const char *hosts) { int nhosts, nfound; hostlist_t hl; char *hostname; assert(set->hl->magic == HOSTLIST_MAGIC); if (!(hl = hostlist_create(hosts))) return (0); nhosts = hostlist_count(hl); nfound = 0; while ((hostname = hostlist_pop(hl)) != NULL) { nfound += hostset_find_host(set, hostname); free(hostname); } hostlist_destroy(hl); return (nhosts == nfound); } int hostset_delete(hostset_t set, const char *hosts) { return hostlist_delete(set->hl, hosts); } int hostset_delete_host(hostset_t set, const char *hostname) { return hostlist_delete_host(set->hl, hostname); } char *hostset_shift(hostset_t set) { return hostlist_shift(set->hl); } char *hostset_pop(hostset_t set) { return hostlist_pop(set->hl); } char *hostset_shift_range(hostset_t set) { return hostlist_shift_range(set->hl); } char *hostset_pop_range(hostset_t set) { return hostlist_pop_range(set->hl); } int hostset_count(hostset_t set) { return hostlist_count(set->hl); } ssize_t hostset_ranged_string(hostset_t set, size_t n, char *buf) { return hostlist_ranged_string(set->hl, n, buf); } ssize_t hostset_deranged_string(hostset_t set, size_t n, char *buf) { return hostlist_deranged_string(set->hl, n, buf); } #if TEST_MAIN int hostlist_nranges(hostlist_t hl) { return hl->nranges; } int hostset_nranges(hostset_t set) { return set->hl->nranges; } /* test iterator functionality on the list of hosts represented * by list */ int iterator_test(char *list) { int j; char buf[1024]; hostlist_t hl = hostlist_create(list); hostset_t set = hostset_create(list); hostlist_iterator_t i = hostlist_iterator_create(hl); hostlist_iterator_t seti = hostset_iterator_create(set); hostlist_iterator_t i2 = hostlist_iterator_create(hl); char *host; hostlist_ranged_string(hl, 1024, buf); printf("iterator_test: hl = `%s' passed in `%s'\n", buf, list); host = hostlist_next(i); printf("first host in list hl = `%s'\n", host); free(host); /* forge ahead three hosts with i2 */ for (j = 0; j < 4; j++) { host = hostlist_next(i2); free(host); } host = hostlist_shift(hl); printf("result of shift(hl) = `%s'\n", host); free(host); host = hostlist_next(i); printf("next host in list hl = `%s'\n", host); free(host); host = hostlist_next(i2); printf("next host for i2 = `%s'\n", host); free(host); hostlist_iterator_destroy(i); hostlist_destroy(hl); hostset_destroy(set); return 1; } int main(int ac, char **av) { char buf[1024000]; int i; char *str; hostlist_t hl1, hl2, hl3; hostset_t set, set1; hostlist_iterator_t iter, iter2; if (!(hl1 = hostlist_create(ac > 1 ? av[1] : NULL))) perror("hostlist_create"); if (!(set = hostset_create(ac > 1 ? av[1] : NULL))) perror("hostlist_create"); hl3 = hostlist_create("f[0-5]"); hostlist_delete(hl3, "f[1-3]"); hostlist_ranged_string(hl3, 102400, buf); printf("after delete = `%s'\n", buf); hostlist_destroy(hl3); for (i = 2; i < ac; i++) { hostlist_push(hl1, av[i]); hostset_insert(set, av[i]); } hostlist_ranged_string(hl1, 102400, buf); printf("ranged = `%s'\n", buf); iterator_test(buf); hostlist_deranged_string(hl1, 10240, buf); printf("deranged = `%s'\n", buf); hostset_ranged_string(set, 1024, buf); printf("hostset = `%s'\n", buf); hostlist_sort(hl1); hostlist_ranged_string(hl1, 1024, buf); printf("sorted = `%s'\n", buf); hostlist_uniq(hl1); hostlist_ranged_string(hl1, 1024, buf); printf("uniqed = `%s'\n", buf); hl2 = hostlist_copy(hl1); printf("pop_range: "); while ((str = hostlist_pop_range(hl2))) { printf("`%s' ", str); free(str); } hostlist_destroy(hl2); printf("\n"); hl2 = hostlist_copy(hl1); printf("shift_range: "); while ((str = hostlist_shift_range(hl2))) { printf("`%s' ", str); free(str); } hostlist_destroy(hl2); printf("\n"); iter = hostset_iterator_create(set); iter2 = hostset_iterator_create(set); hostlist_iterator_destroy(iter2); printf("next: "); while ((str = hostlist_next(iter))) { printf("`%s' ", str); free(str); } printf("\n"); hostlist_iterator_reset(iter); printf("next_range: "); while ((str = hostlist_next_range(iter))) { printf("`%s' ", str); free(str); } printf("\n"); printf("nranges = %d\n", hostset_nranges(set)); hostset_ranged_string(set, 1024, buf); printf("set = %s\n", buf); hostset_destroy(set); hostlist_destroy(hl1); return 0; } #endif /* TEST_MAIN */ /* * vi: tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/liblsd/hostlist.h000066400000000000000000000272561467035776500174730ustar00rootroot00000000000000/*****************************************************************************\ * $LSDId: commit c08d251f3cc9b1a5b69a268f952d64f990366835 $ ***************************************************************************** * Copyright (C) 2002 The Regents of the University of California. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). * Written by Mark Grondona * UCRL-CODE-2002-040. * * This file is part of SLURM, a resource management program. * For details, see . * * SLURM 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. * * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along * with SLURM; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. \*****************************************************************************/ #ifndef _HOSTLIST_H #define _HOSTLIST_H #include /* Notes: * * If WITH_LSD_FATAL_ERROR_FUNC is defined, the linker will expect to * find and external lsd_fatal_error(file,line,mesg) function. By default, * lsd_fatal_error(file,line,mesg) is a macro definition that outputs an * error message to stderr. This macro may be redefined to invoke another * routine instead. e.g.: * * #define lsd_fatal_error(file,line,mesg) \ * error("%s:%s %s\n",file,line,mesg); * * If WITH_LSD_NOMEM_ERROR_FUNC is defined, the linker will expect to * find an external lsd_nomem_error(file,line,mesg) function. By default, * lsd_nomem_error(file,line,mesg) is a macro definition that returns NULL. * This macro may be redefined to invoke another routine instead. * * If WITH_PTHREADS is defined, these routines will be thread-safe. * */ /* The hostlist opaque data type * * A hostlist is a list of hostnames optimized for a prefixXXXX style * naming convention, where XXXX is a decimal, numeric suffix. */ typedef struct hostlist * hostlist_t; /* A hostset is a special case of a hostlist. It: * * 1. never contains duplicates * 2. is always sorted * (Note: sort occurs first on alphanumeric prefix -- where prefix * matches, numeric suffixes will be sorted *by value*) */ typedef struct hostset * hostset_t; /* The hostlist iterator type (may be used with a hostset as well) * used for non-destructive access to hostlist members. * */ typedef struct hostlist_iterator * hostlist_iterator_t; /* ----[ hostlist_t functions: ]---- */ /* ----[ hostlist creation and destruction ]---- */ /* * hostlist_create(): * * Create a new hostlist from a string representation. * * The string representation (str) may contain one or more hostnames or * bracketed hostlists separated by either `,' or whitespace. A bracketed * hostlist is denoted by a common prefix followed by a list of numeric * ranges contained within brackets: e.g. "tux[0-5,12,20-25]" * * Note: if this module is compiled with WANT_RECKLESS_HOSTRANGE_EXPANSION * defined, a much more loose interpretation of host ranges is used. * Reckless hostrange expansion allows all of the following (in addition to * bracketed hostlists): * * o tux0-5,tux12,tux20-25 * o tux0-tux5,tux12,tux20-tux25 * o tux0-5,12,20-25 * * If str is NULL, and empty hostlist is created and returned. * * If the create fails, hostlist_create() returns NULL. * * The returned hostlist must be freed with hostlist_destroy() * */ hostlist_t hostlist_create(const char *hostlist); /* hostlist_copy(): * * Allocate a copy of a hostlist object. Returned hostlist must be freed * with hostlist_destroy. */ hostlist_t hostlist_copy(const hostlist_t hl); /* hostlist_destroy(): * * Destroy a hostlist object. Frees all memory allocated to the hostlist. */ void hostlist_destroy(hostlist_t hl); /* ----[ hostlist list operations ]---- */ /* hostlist_push(): * * push a string representation of hostnames onto a hostlist. * * The hosts argument may take the same form as in hostlist_create() * * Returns the number of hostnames inserted into the list, * or 0 on failure. */ int hostlist_push(hostlist_t hl, const char *hosts); /* hostlist_push_host(): * * Push a single host onto the hostlist hl. * This function is more efficient than hostlist_push() for a single * hostname, since the argument does not need to be checked for ranges. * * return value is 1 for success, 0 for failure. */ int hostlist_push_host(hostlist_t hl, const char *host); /* hostlist_push_list(): * * Push a hostlist (hl2) onto another list (hl1) * * Returns 1 for success, 0 for failure. * */ int hostlist_push_list(hostlist_t hl1, hostlist_t hl2); /* hostlist_pop(): * * Returns the string representation of the last host pushed onto the list * or NULL if hostlist is empty or there was an error allocating memory. * The host is removed from the hostlist. * * Note: Caller is responsible for freeing the returned memory. */ char * hostlist_pop(hostlist_t hl); char * hostlist_nth(hostlist_t hl, int n); /* hostlist_shift(): * * Returns the string representation of the first host in the hostlist * or NULL if the hostlist is empty or there was an error allocating memory. * The host is removed from the hostlist. * * Note: Caller is responsible for freeing the returned memory. */ char * hostlist_shift(hostlist_t hl); /* hostlist_pop_range(): * * Pop the last bracketed list of hosts of the hostlist hl. * Returns the string representation in bracketed list form. * All hosts associated with the returned list are removed * from hl. * * Caller is responsible for freeing returned memory */ char * hostlist_pop_range(hostlist_t hl); /* hostlist_shift_range(): * * Shift the first bracketed hostlist (improperly: range) off the * hostlist hl. Returns the string representation in bracketed list * form. All hosts associated with the list are removed from the * hostlist. * * Caller is responsible for freeing returned memory. */ char * hostlist_shift_range(hostlist_t hl); /* hostlist_find(): * * Searches hostlist hl for the first host matching hostname * and returns position in list if found. * * Returns -1 if host is not found. * */ int hostlist_find(hostlist_t hl, const char *hostname); /* hostlist_delete(): * * Deletes all hosts in the list represented by `hosts' * * Returns the number of hosts successfully deleted */ int hostlist_delete(hostlist_t hl, const char *hosts); /* hostlist_delete_host(): * * Deletes the first host that matches `hostname' from the hostlist hl. * Note: "hostname" argument cannot contain a range of hosts * (see hostlist_delete() for this functionality.) * * Returns 1 if successful, 0 if hostname is not found in list. */ int hostlist_delete_host(hostlist_t hl, const char *hostname); /* hostlist_delete_nth(): * * Deletes the host from position n in the hostlist. * * Returns 1 if successful 0 on error. * */ int hostlist_delete_nth(hostlist_t hl, int n); /* hostlist_count(): * * Return the number of hosts in hostlist hl. */ int hostlist_count(hostlist_t hl); /* hostlist_is_empty(): return true if hostlist is empty. */ #define hostlist_is_empty(__hl) ( hostlist_count(__hl) == 0 ) /* ----[ Other hostlist operations ]---- */ /* hostlist_sort(): * * Sort the hostlist hl. * */ void hostlist_sort(hostlist_t hl); /* hostlist_uniq(): * * Sort the hostlist hl and remove duplicate entries. * */ void hostlist_uniq(hostlist_t hl); /* ----[ hostlist print functions ]---- */ /* hostlist_ranged_string(): * * Write the string representation of the hostlist hl into buf, * writing at most n chars. Returns the number of bytes written, * or -1 if truncation occurred. * * The result will be NULL terminated. * * hostlist_ranged_string() will write a bracketed hostlist representation * where possible. */ ssize_t hostlist_ranged_string(hostlist_t hl, size_t n, char *buf); ssize_t hostset_ranged_string(hostset_t hs, size_t n, char *buf); /* hostlist_deranged_string(): * * Writes the string representation of the hostlist hl into buf, * writing at most n chars. Returns the number of bytes written, * or -1 if truncation occurred. * * hostlist_deranged_string() will not attempt to write a bracketed * hostlist representation. Every hostname will be explicitly written. */ ssize_t hostlist_deranged_string(hostlist_t hl, size_t n, char *buf); ssize_t hostset_deranged_string(hostset_t hs, size_t n, char *buf); /* ----[ hostlist utility functions ]---- */ /* hostlist_nranges(): * * Return the number of ranges currently held in hostlist hl. */ int hostlist_nranges(hostlist_t hl); /* ----[ hostlist iterator functions ]---- */ /* hostlist_iterator_create(): * * Creates and returns a hostlist iterator used for non destructive * access to a hostlist or hostset. Returns NULL on failure. */ hostlist_iterator_t hostlist_iterator_create(hostlist_t hl); /* hostset_iterator_create(): * * Same as hostlist_iterator_create(), but creates a hostlist_iterator * from a hostset. */ hostlist_iterator_t hostset_iterator_create(hostset_t set); /* hostlist_iterator_destroy(): * * Destroys a hostlist iterator. */ void hostlist_iterator_destroy(hostlist_iterator_t i); /* hostlist_iterator_reset(): * * Reset an iterator to the beginning of the list. */ void hostlist_iterator_reset(hostlist_iterator_t i); /* hostlist_next(): * * Returns a pointer to the next hostname on the hostlist * or NULL at the end of the list * * The caller is responsible for freeing the returned memory. */ char * hostlist_next(hostlist_iterator_t i); /* hostlist_next_range(): * * Returns the next bracketed hostlist or NULL if the iterator i is * at the end of the list. * * The caller is responsible for freeing the returned memory. * */ char * hostlist_next_range(hostlist_iterator_t i); /* hostlist_remove(): * Removes the last host returned by hostlist iterator i * * Returns 1 for success, 0 for failure. */ int hostlist_remove(hostlist_iterator_t i); /* ----[ hostset operations ]---- */ /* hostset_create(): * * Create a new hostset object from a string representation of a list of * hosts. See hostlist_create() for valid hostlist forms. */ hostset_t hostset_create(const char *hostlist); /* hostset_copy(): * * Copy a hostset object. Returned set must be freed with hostset_destroy(). */ hostset_t hostset_copy(hostset_t set); /* hostset_destroy(): */ void hostset_destroy(hostset_t set); /* hostset_insert(): * Add a host or list of hosts into hostset "set." * * Returns number of hosts successfully added to "set" * (insertion of a duplicate is not considered successful) */ int hostset_insert(hostset_t set, const char *hosts); /* hostset_delete(): * Delete a host or list of hosts from hostset "set." * Returns number of hosts deleted from set. */ int hostset_delete(hostset_t set, const char *hosts); /* hostset_within(): * Return 1 if all hosts specified by "hosts" are within the hostset "set" * Retrun 0 if every host in "hosts" is not in the hostset "set" */ int hostset_within(hostset_t set, const char *hosts); /* hostset_shift(): * hostset equivalent to hostlist_shift() */ char * hostset_shift(hostset_t set); /* hostset_shift_range(): * hostset eqivalent to hostlist_shift_range() */ char * hostset_shift_range(hostset_t set); /* hostset_count(): * Count the number of hosts currently in hostset */ int hostset_count(hostset_t set); #endif /* !_HOSTLIST_H */ powerman-2.4.4/src/liblsd/list.c000066400000000000000000000507021467035776500165600ustar00rootroot00000000000000/***************************************************************************** * Copyright (C) 2001-2002 The Regents of the University of California. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). * Written by Chris Dunlap . * * This file is from LSD-Tools, the LLNL Software Development Toolbox. * * LSD-Tools 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. * * LSD-Tools is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with LSD-Tools; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***************************************************************************** * Refer to "list.h" for documentation on public functions. *****************************************************************************/ #ifdef HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #ifdef WITH_PTHREADS # include #endif /* WITH_PTHREADS */ #include #include #include #include #include "list.h" /********************* * lsd_fatal_error * *********************/ #ifdef WITH_LSD_FATAL_ERROR_FUNC # undef lsd_fatal_error extern void lsd_fatal_error(char *file, int line, char *mesg); #else /* !WITH_LSD_FATAL_ERROR_FUNC */ # ifndef lsd_fatal_error # include # include # include # define lsd_fatal_error(file, line, mesg) \ do { \ fprintf(stderr, "ERROR: [%s:%d] %s: %s\n", \ file, line, mesg, strerror(errno)); \ } while (0) # endif /* !lsd_fatal_error */ #endif /* !WITH_LSD_FATAL_ERROR_FUNC */ /********************* * lsd_nomem_error * *********************/ #ifdef WITH_LSD_NOMEM_ERROR_FUNC # undef lsd_nomem_error extern void * lsd_nomem_error(char *file, int line, char *mesg); #else /* !WITH_LSD_NOMEM_ERROR_FUNC */ # ifndef lsd_nomem_error # define lsd_nomem_error(file, line, mesg) (NULL) # endif /* !lsd_nomem_error */ #endif /* !WITH_LSD_NOMEM_ERROR_FUNC */ /*************** * Constants * ***************/ #define LIST_ALLOC 32 #define LIST_MAGIC 0xDEADBEEF /**************** * Data Types * ****************/ struct listNode { void *data; /* node's data */ struct listNode *next; /* next node in list */ }; struct listIterator { struct list *list; /* the list being iterated */ struct listNode *pos; /* the next node to be iterated */ struct listNode **prev; /* addr of 'next' ptr to prv It node */ struct listIterator *iNext; /* iterator chain for list_destroy() */ #ifndef NDEBUG unsigned int magic; /* sentinel for asserting validity */ #endif /* !NDEBUG */ }; struct list { struct listNode *head; /* head of the list */ struct listNode **tail; /* addr of last node's 'next' ptr */ struct listIterator *iNext; /* iterator chain for list_destroy() */ ListDelF fDel; /* function to delete node data */ int count; /* number of nodes in list */ #ifdef WITH_PTHREADS pthread_mutex_t mutex; /* mutex to protect access to list */ #endif /* WITH_PTHREADS */ #ifndef NDEBUG unsigned int magic; /* sentinel for asserting validity */ #endif /* !NDEBUG */ }; typedef struct listNode * ListNode; /**************** * Prototypes * ****************/ static void * list_node_create (List l, ListNode *pp, void *x); static void * list_node_destroy (List l, ListNode *pp); static List list_alloc (void); static void list_free (List l); static ListNode list_node_alloc (void); static void list_node_free (ListNode p); static ListIterator list_iterator_alloc (void); static void list_iterator_free (ListIterator i); static void * list_alloc_aux (int size, void *pfreelist); static void list_free_aux (void *x, void *pfreelist); /*************** * Variables * ***************/ static List list_free_lists = NULL; static ListNode list_free_nodes = NULL; static ListIterator list_free_iterators = NULL; #ifdef WITH_PTHREADS static pthread_mutex_t list_free_lock = PTHREAD_MUTEX_INITIALIZER; #endif /* WITH_PTHREADS */ /************ * Macros * ************/ #ifdef WITH_PTHREADS # define list_mutex_init(mutex) \ do { \ int e = pthread_mutex_init(mutex, NULL); \ if (e != 0) { \ errno = e; \ lsd_fatal_error(__FILE__, __LINE__, "list mutex init"); \ abort(); \ } \ } while (0) # define list_mutex_lock(mutex) \ do { \ int e = pthread_mutex_lock(mutex); \ if (e != 0) { \ errno = e; \ lsd_fatal_error(__FILE__, __LINE__, "list mutex lock"); \ abort(); \ } \ } while (0) # define list_mutex_unlock(mutex) \ do { \ int e = pthread_mutex_unlock(mutex); \ if (e != 0) { \ errno = e; \ lsd_fatal_error(__FILE__, __LINE__, "list mutex unlock"); \ abort(); \ } \ } while (0) # define list_mutex_destroy(mutex) \ do { \ int e = pthread_mutex_destroy(mutex); \ if (e != 0) { \ errno = e; \ lsd_fatal_error(__FILE__, __LINE__, "list mutex destroy"); \ abort(); \ } \ } while (0) # ifndef NDEBUG static int list_mutex_is_locked (pthread_mutex_t *mutex); # endif /* !NDEBUG */ #else /* !WITH_PTHREADS */ # define list_mutex_init(mutex) # define list_mutex_lock(mutex) # define list_mutex_unlock(mutex) # define list_mutex_destroy(mutex) # define list_mutex_is_locked(mutex) (1) #endif /* !WITH_PTHREADS */ /*************** * Functions * ***************/ List list_create (ListDelF f) { List l; if (!(l = list_alloc())) return(lsd_nomem_error(__FILE__, __LINE__, "list create")); l->head = NULL; l->tail = &l->head; l->iNext = NULL; l->fDel = f; l->count = 0; list_mutex_init(&l->mutex); assert(l->magic = LIST_MAGIC); /* set magic via assert abuse */ return(l); } void list_destroy (List l) { ListIterator i, iTmp; ListNode p, pTmp; assert(l != NULL); list_mutex_lock(&l->mutex); assert(l->magic == LIST_MAGIC); i = l->iNext; while (i) { assert(i->magic == LIST_MAGIC); iTmp = i->iNext; assert(i->magic = ~LIST_MAGIC); /* clear magic via assert abuse */ list_iterator_free(i); i = iTmp; } p = l->head; while (p) { pTmp = p->next; if (p->data && l->fDel) l->fDel(p->data); list_node_free(p); p = pTmp; } assert(l->magic = ~LIST_MAGIC); /* clear magic via assert abuse */ list_mutex_unlock(&l->mutex); list_mutex_destroy(&l->mutex); list_free(l); return; } int list_is_empty (List l) { int n; assert(l != NULL); list_mutex_lock(&l->mutex); assert(l->magic == LIST_MAGIC); n = l->count; list_mutex_unlock(&l->mutex); return(n == 0); } int list_count (List l) { int n; assert(l != NULL); list_mutex_lock(&l->mutex); assert(l->magic == LIST_MAGIC); n = l->count; list_mutex_unlock(&l->mutex); return(n); } void * list_append (List l, void *x) { void *v; assert(l != NULL); assert(x != NULL); list_mutex_lock(&l->mutex); assert(l->magic == LIST_MAGIC); v = list_node_create(l, l->tail, x); list_mutex_unlock(&l->mutex); return(v); } void * list_prepend (List l, void *x) { void *v; assert(l != NULL); assert(x != NULL); list_mutex_lock(&l->mutex); assert(l->magic == LIST_MAGIC); v = list_node_create(l, &l->head, x); list_mutex_unlock(&l->mutex); return(v); } void * list_find_first (List l, ListFindF f, void *key) { ListNode p; void *v = NULL; assert(l != NULL); assert(f != NULL); list_mutex_lock(&l->mutex); assert(l->magic == LIST_MAGIC); for (p=l->head; p; p=p->next) { if (f(p->data, key)) { v = p->data; break; } } list_mutex_unlock(&l->mutex); return(v); } int list_delete_all (List l, ListFindF f, void *key) { ListNode *pp; void *v; int n = 0; assert(l != NULL); assert(f != NULL); list_mutex_lock(&l->mutex); assert(l->magic == LIST_MAGIC); pp = &l->head; while (*pp) { if (f((*pp)->data, key)) { if ((v = list_node_destroy(l, pp))) { if (l->fDel) l->fDel(v); n++; } } else { pp = &(*pp)->next; } } list_mutex_unlock(&l->mutex); return(n); } int list_for_each (List l, ListForF f, void *arg) { ListNode p; int n = 0; assert(l != NULL); assert(f != NULL); list_mutex_lock(&l->mutex); assert(l->magic == LIST_MAGIC); for (p=l->head; p; p=p->next) { n++; if (f(p->data, arg) < 0) { n = -n; break; } } list_mutex_unlock(&l->mutex); return(n); } void list_sort (List l, ListCmpF f) { /* Note: Time complexity O(n^2). */ ListNode *pp, *ppPrev, *ppPos, pTmp; ListIterator i; assert(l != NULL); assert(f != NULL); list_mutex_lock(&l->mutex); assert(l->magic == LIST_MAGIC); if (l->count > 1) { ppPrev = &l->head; pp = &(*ppPrev)->next; while (*pp) { if (f((*pp)->data, (*ppPrev)->data) < 0) { ppPos = &l->head; while (f((*pp)->data, (*ppPos)->data) >= 0) ppPos = &(*ppPos)->next; pTmp = (*pp)->next; (*pp)->next = *ppPos; *ppPos = *pp; *pp = pTmp; if (ppPrev == ppPos) ppPrev = &(*ppPrev)->next; } else { ppPrev = pp; pp = &(*pp)->next; } } l->tail = pp; for (i=l->iNext; i; i=i->iNext) { assert(i->magic == LIST_MAGIC); i->pos = i->list->head; i->prev = &i->list->head; } } list_mutex_unlock(&l->mutex); return; } void * list_push (List l, void *x) { void *v; assert(l != NULL); assert(x != NULL); list_mutex_lock(&l->mutex); assert(l->magic == LIST_MAGIC); v = list_node_create(l, &l->head, x); list_mutex_unlock(&l->mutex); return(v); } void * list_pop (List l) { void *v; assert(l != NULL); list_mutex_lock(&l->mutex); assert(l->magic == LIST_MAGIC); v = list_node_destroy(l, &l->head); list_mutex_unlock(&l->mutex); return(v); } void * list_peek (List l) { void *v; assert(l != NULL); list_mutex_lock(&l->mutex); assert(l->magic == LIST_MAGIC); v = (l->head) ? l->head->data : NULL; list_mutex_unlock(&l->mutex); return(v); } void * list_enqueue (List l, void *x) { void *v; assert(l != NULL); assert(x != NULL); list_mutex_lock(&l->mutex); assert(l->magic == LIST_MAGIC); v = list_node_create(l, l->tail, x); list_mutex_unlock(&l->mutex); return(v); } void * list_dequeue (List l) { void *v; assert(l != NULL); list_mutex_lock(&l->mutex); assert(l->magic == LIST_MAGIC); v = list_node_destroy(l, &l->head); list_mutex_unlock(&l->mutex); return(v); } ListIterator list_iterator_create (List l) { ListIterator i; assert(l != NULL); if (!(i = list_iterator_alloc())) return(lsd_nomem_error(__FILE__, __LINE__, "list iterator create")); i->list = l; list_mutex_lock(&l->mutex); assert(l->magic == LIST_MAGIC); i->pos = l->head; i->prev = &l->head; i->iNext = l->iNext; l->iNext = i; assert(i->magic = LIST_MAGIC); /* set magic via assert abuse */ list_mutex_unlock(&l->mutex); return(i); } void list_iterator_reset (ListIterator i) { assert(i != NULL); assert(i->magic == LIST_MAGIC); list_mutex_lock(&i->list->mutex); assert(i->list->magic == LIST_MAGIC); i->pos = i->list->head; i->prev = &i->list->head; list_mutex_unlock(&i->list->mutex); return; } void list_iterator_destroy (ListIterator i) { ListIterator *pi; assert(i != NULL); assert(i->magic == LIST_MAGIC); list_mutex_lock(&i->list->mutex); assert(i->list->magic == LIST_MAGIC); for (pi=&i->list->iNext; *pi; pi=&(*pi)->iNext) { assert((*pi)->magic == LIST_MAGIC); if (*pi == i) { *pi = (*pi)->iNext; break; } } list_mutex_unlock(&i->list->mutex); assert(i->magic = ~LIST_MAGIC); /* clear magic via assert abuse */ list_iterator_free(i); return; } void * list_next (ListIterator i) { ListNode p; assert(i != NULL); assert(i->magic == LIST_MAGIC); list_mutex_lock(&i->list->mutex); assert(i->list->magic == LIST_MAGIC); if ((p = i->pos)) i->pos = p->next; if (*i->prev != p) i->prev = &(*i->prev)->next; list_mutex_unlock(&i->list->mutex); return(p ? p->data : NULL); } void * list_insert (ListIterator i, void *x) { void *v; assert(i != NULL); assert(x != NULL); assert(i->magic == LIST_MAGIC); list_mutex_lock(&i->list->mutex); assert(i->list->magic == LIST_MAGIC); v = list_node_create(i->list, i->prev, x); list_mutex_unlock(&i->list->mutex); return(v); } void * list_find (ListIterator i, ListFindF f, void *key) { void *v; assert(i != NULL); assert(f != NULL); assert(i->magic == LIST_MAGIC); while ((v=list_next(i)) && !f(v,key)) {;} return(v); } void * list_remove (ListIterator i) { void *v = NULL; assert(i != NULL); assert(i->magic == LIST_MAGIC); list_mutex_lock(&i->list->mutex); assert(i->list->magic == LIST_MAGIC); if (*i->prev != i->pos) v = list_node_destroy(i->list, i->prev); list_mutex_unlock(&i->list->mutex); return(v); } int list_delete (ListIterator i) { void *v; assert(i != NULL); assert(i->magic == LIST_MAGIC); if ((v = list_remove(i))) { if (i->list->fDel) i->list->fDel(v); return(1); } return(0); } static void * list_node_create (List l, ListNode *pp, void *x) { /* Inserts data pointed to by [x] into list [l] after [pp], * the address of the previous node's "next" ptr. * Returns a ptr to data [x], or NULL if insertion fails. * This routine assumes the list is already locked upon entry. */ ListNode p; ListIterator i; assert(l != NULL); assert(l->magic == LIST_MAGIC); assert(list_mutex_is_locked(&l->mutex)); assert(pp != NULL); assert(x != NULL); if (!(p = list_node_alloc())) return(lsd_nomem_error(__FILE__, __LINE__, "list node create")); p->data = x; if (!(p->next = *pp)) l->tail = &p->next; *pp = p; l->count++; for (i=l->iNext; i; i=i->iNext) { assert(i->magic == LIST_MAGIC); if (i->prev == pp) i->prev = &p->next; else if (i->pos == p->next) i->pos = p; assert((i->pos == *i->prev) || (i->pos == (*i->prev)->next)); } return(x); } static void * list_node_destroy (List l, ListNode *pp) { /* Removes the node pointed to by [*pp] from from list [l], * where [pp] is the address of the previous node's "next" ptr. * Returns the data ptr associated with list item being removed, * or NULL if [*pp] points to the NULL element. * This routine assumes the list is already locked upon entry. */ void *v; ListNode p; ListIterator i; assert(l != NULL); assert(l->magic == LIST_MAGIC); assert(list_mutex_is_locked(&l->mutex)); assert(pp != NULL); if (!(p = *pp)) return(NULL); v = p->data; if (!(*pp = p->next)) l->tail = pp; l->count--; for (i=l->iNext; i; i=i->iNext) { assert(i->magic == LIST_MAGIC); if (i->pos == p) i->pos = p->next, i->prev = pp; else if (i->prev == &p->next) i->prev = pp; assert((i->pos == *i->prev) || (i->pos == (*i->prev)->next)); } list_node_free(p); return(v); } static List list_alloc (void) { return(list_alloc_aux(sizeof(struct list), &list_free_lists)); } static void list_free (List l) { list_free_aux(l, &list_free_lists); return; } static ListNode list_node_alloc (void) { return(list_alloc_aux(sizeof(struct listNode), &list_free_nodes)); } static void list_node_free (ListNode p) { list_free_aux(p, &list_free_nodes); return; } static ListIterator list_iterator_alloc (void) { return(list_alloc_aux(sizeof(struct listIterator), &list_free_iterators)); } static void list_iterator_free (ListIterator i) { list_free_aux(i, &list_free_iterators); return; } static void * list_alloc_aux (int size, void *pfreelist) { /* Allocates an object of [size] bytes from the freelist [*pfreelist]. * Memory is added to the freelist in chunks of size LIST_ALLOC. * Returns a ptr to the object, or NULL if the memory request fails. */ void **px; void **pfree = pfreelist; void **plast; assert(sizeof(char) == 1); assert(size >= sizeof(void *)); assert(pfreelist != NULL); assert(LIST_ALLOC > 0); list_mutex_lock(&list_free_lock); if (!*pfree) { if ((*pfree = malloc(LIST_ALLOC * size))) { px = *pfree; plast = (void **) ((char *) *pfree + ((LIST_ALLOC - 1) * size)); while (px < plast) *px = (char *) px + size, px = *px; *plast = NULL; } } if ((px = *pfree)) *pfree = *px; else errno = ENOMEM; list_mutex_unlock(&list_free_lock); return(px); } static void list_free_aux (void *x, void *pfreelist) { /* Frees the object [x], returning it to the freelist [*pfreelist]. */ void **px = x; void **pfree = pfreelist; assert(x != NULL); assert(pfreelist != NULL); list_mutex_lock(&list_free_lock); *px = *pfree; *pfree = px; list_mutex_unlock(&list_free_lock); return; } #ifndef NDEBUG #ifdef WITH_PTHREADS static int list_mutex_is_locked (pthread_mutex_t *mutex) { /* Returns true if the mutex is locked; o/w, returns false. */ int rc; assert(mutex != NULL); rc = pthread_mutex_trylock(mutex); return(rc == EBUSY ? 1 : 0); } #endif /* WITH_PTHREADS */ #endif /* !NDEBUG */ powerman-2.4.4/src/liblsd/list.h000066400000000000000000000214611467035776500165650ustar00rootroot00000000000000/***************************************************************************** * Copyright (C) 2001-2002 The Regents of the University of California. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). * Written by Chris Dunlap . * * This file is from LSD-Tools, the LLNL Software Development Toolbox. * * LSD-Tools 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. * * LSD-Tools is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with LSD-Tools; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *****************************************************************************/ #ifndef LSD_LIST_H #define LSD_LIST_H /*********** * Notes * ***********/ /* * If NDEBUG is not defined, internal debug code will be enabled. This is * intended for development use only and production code should define NDEBUG. * * If WITH_LSD_FATAL_ERROR_FUNC is defined, the linker will expect to * find an external lsd_fatal_error(file,line,mesg) function. By default, * lsd_fatal_error(file,line,mesg) is a macro definition that outputs an * error message to stderr. This macro may be redefined to invoke another * routine instead. * * If WITH_LSD_NOMEM_ERROR_FUNC is defined, the linker will expect to * find an external lsd_nomem_error(file,line,mesg) function. By default, * lsd_nomem_error(file,line,mesg) is a macro definition that returns NULL. * This macro may be redefined to invoke another routine instead. * * If WITH_PTHREADS is defined, these routines will be thread-safe. */ /**************** * Data Types * ****************/ typedef struct list * List; /* * List opaque data type. */ typedef struct listIterator * ListIterator; /* * List Iterator opaque data type. */ typedef void (*ListDelF) (void *x); /* * Function prototype to deallocate data stored in a list. * This function is responsible for freeing all memory associated * with an item, including all subordinate items (if applicable). */ typedef int (*ListCmpF) (void *x, void *y); /* * Function prototype for comparing two items in a list. * Returns less-than-zero if (xy). */ typedef int (*ListFindF) (void *x, void *key); /* * Function prototype for matching items in a list. * Returns non-zero if (x==key); o/w returns zero. */ typedef int (*ListForF) (void *x, void *arg); /* * Function prototype for operating on each item in a list. * Returns less-than-zero on error. */ /******************************* * General-Purpose Functions * *******************************/ List list_create (ListDelF f); /* * Creates and returns a new empty list, or lsd_nomem_error() on failure. * The deletion function [f] is used to deallocate memory used by items * in the list; if this is NULL, memory associated with these items * will not be freed when the list is destroyed. * Note: Abandoning a list without calling list_destroy() will result * in a memory leak. */ void list_destroy (List l); /* * Destroys list [l], freeing memory used for list iterators and the * list itself; if a deletion function was specified when the list * was created, it will be called for each item in the list. */ int list_is_empty (List l); /* * Returns non-zero if list [l] is empty; o/w returns zero. */ int list_count (List l); /* * Returns the number of items in list [l]. */ /*************************** * List Access Functions * ***************************/ void * list_append (List l, void *x); /* * Inserts data [x] at the end of list [l]. * Returns the data's ptr, or lsd_nomem_error() if insertion failed. */ void * list_prepend (List l, void *x); /* * Inserts data [x] at the beginning of list [l]. * Returns the data's ptr, or lsd_nomem_error() if insertion failed. */ void * list_find_first (List l, ListFindF f, void *key); /* * Traverses list [l] using [f] to match each item with [key]. * Returns a ptr to the first item for which the function [f] * returns non-zero, or NULL if no such item is found. * Note: This function differs from list_find() in that it does not require * a list iterator; it should only be used when all list items are known * to be unique (according to the function [f]). */ int list_delete_all (List l, ListFindF f, void *key); /* * Traverses list [l] using [f] to match each item with [key]. * Removes all items from the list for which the function [f] returns * non-zero; if a deletion function was specified when the list was * created, it will be called to deallocate each item being removed. * Returns a count of the number of items removed from the list. */ int list_for_each (List l, ListForF f, void *arg); /* * For each item in list [l], invokes the function [f] with [arg]. * Returns a count of the number of items on which [f] was invoked. * If [f] returns <0 for a given item, the iteration is aborted and the * function returns the negative of that item's position in the list. */ void list_sort (List l, ListCmpF f); /* * Sorts list [l] into ascending order according to the function [f]. * Note: Sorting a list resets all iterators associated with the list. * Note: The sort algorithm is stable. */ /**************************** * Stack Access Functions * ****************************/ void * list_push (List l, void *x); /* * Pushes data [x] onto the top of stack [l]. * Returns the data's ptr, or lsd_nomem_error() if insertion failed. */ void * list_pop (List l); /* * Pops the data item at the top of the stack [l]. * Returns the data's ptr, or NULL if the stack is empty. */ void * list_peek (List l); /* * Peeks at the data item at the top of the stack (or head of the queue) [l]. * Returns the data's ptr, or NULL if the stack (or queue) is empty. * Note: The item is not removed from the list. */ /**************************** * Queue Access Functions * ****************************/ void * list_enqueue (List l, void *x); /* * Enqueues data [x] at the tail of queue [l]. * Returns the data's ptr, or lsd_nomem_error() if insertion failed. */ void * list_dequeue (List l); /* * Dequeues the data item at the head of the queue [l]. * Returns the data's ptr, or NULL if the queue is empty. */ /***************************** * List Iterator Functions * *****************************/ ListIterator list_iterator_create (List l); /* * Creates and returns a list iterator for non-destructively traversing * list [l], or lsd_nomem_error() on failure. */ void list_iterator_reset (ListIterator i); /* * Resets the list iterator [i] to start traversal at the beginning * of the list. */ void list_iterator_destroy (ListIterator i); /* * Destroys the list iterator [i]; list iterators not explicitly destroyed * in this manner will be destroyed when the list is deallocated via * list_destroy(). */ void * list_next (ListIterator i); /* * Returns a ptr to the next item's data, * or NULL once the end of the list is reached. * Example: i=list_iterator_create(i); while ((x=list_next(i))) {...} */ void * list_insert (ListIterator i, void *x); /* * Inserts data [x] immediately before the last item returned via list * iterator [i]; once the list iterator reaches the end of the list, * insertion is made at the list's end. * Returns the data's ptr, or lsd_nomem_error() if insertion failed. */ void * list_find (ListIterator i, ListFindF f, void *key); /* * Traverses the list from the point of the list iterator [i] * using [f] to match each item with [key]. * Returns a ptr to the next item for which the function [f] * returns non-zero, or NULL once the end of the list is reached. * Example: i=list_iterator_reset(i); while ((x=list_find(i,f,k))) {...} */ void * list_remove (ListIterator i); /* * Removes from the list the last item returned via list iterator [i] * and returns the data's ptr. * Note: The client is responsible for freeing the returned data. */ int list_delete (ListIterator i); /* * Removes from the list the last item returned via list iterator [i]; * if a deletion function was specified when the list was created, * it will be called to deallocate the item being removed. * Returns a count of the number of items removed from the list * (ie, '1' if the item was removed, and '0' otherwise). */ #endif /* !LSD_LIST_H */ powerman-2.4.4/src/libtap/000077500000000000000000000000001467035776500154375ustar00rootroot00000000000000powerman-2.4.4/src/libtap/Makefile.am000066400000000000000000000001761467035776500174770ustar00rootroot00000000000000AM_CFLAGS = \ $(WARNING_CFLAGS) AM_LDFLAGS = AM_CPPFLAGS = check_LTLIBRARIES = libtap.la libtap_la_SOURCES = tap.c tap.h powerman-2.4.4/src/libtap/tap.c000066400000000000000000000204271467035776500163740ustar00rootroot00000000000000/* libtap - Write tests in C Copyright 2012 Jake Gelbman This file is licensed under the LGPL */ #define _DEFAULT_SOURCE 1 #include #include #include #include #include "tap.h" static int expected_tests = NO_PLAN; static int failed_tests; static int current_test; static char *todo_mesg; static char * vstrdupf (const char *fmt, va_list args) { char *str; int size; va_list args2; va_copy(args2, args); if (!fmt) fmt = ""; size = vsnprintf(NULL, 0, fmt, args2) + 2; str = malloc(size); if (!str) { perror("malloc error"); exit(1); } vsprintf(str, fmt, args); va_end(args2); return str; } void tap_plan (int tests, const char *fmt, ...) { expected_tests = tests; if (tests == SKIP_ALL) { char *why; va_list args; va_start(args, fmt); why = vstrdupf(fmt, args); va_end(args); printf("1..0 "); diag("SKIP %s\n", why); exit(0); } if (tests != NO_PLAN) { printf("1..%d\n", tests); } } int vok_at_loc (const char *file, int line, int test, const char *fmt, va_list args) { char *name = vstrdupf(fmt, args); if (!test) { printf("not "); } printf("ok %d", ++current_test); if (*name) printf(" - %s", name); if (todo_mesg) { printf(" # TODO"); if (*todo_mesg) printf(" %s", todo_mesg); } printf("\n"); if (!test) { printf("# Failed "); if (todo_mesg) printf("(TODO) "); printf("test "); if (*name) printf("'%s'\n# ", name); printf("at %s line %d.\n", file, line); if (!todo_mesg) failed_tests++; } free(name); return test; } int ok_at_loc (const char *file, int line, int test, const char *fmt, ...) { va_list args; va_start(args, fmt); vok_at_loc(file, line, test, fmt, args); va_end(args); return test; } static int mystrcmp (const char *a, const char *b) { return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b); } #define eq(a, b) (!mystrcmp(a, b)) #define ne(a, b) (mystrcmp(a, b)) int is_at_loc (const char *file, int line, const char *got, const char *expected, const char *fmt, ...) { int test = eq(got, expected); va_list args; va_start(args, fmt); vok_at_loc(file, line, test, fmt, args); va_end(args); if (!test) { diag(" got: '%s'", got); diag(" expected: '%s'", expected); } return test; } int isnt_at_loc (const char *file, int line, const char *got, const char *expected, const char *fmt, ...) { int test = ne(got, expected); va_list args; va_start(args, fmt); vok_at_loc(file, line, test, fmt, args); va_end(args); if (!test) { diag(" got: '%s'", got); diag(" expected: anything else"); } return test; } int cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b, const char *fmt, ...) { int test = eq(op, "||") ? a || b : eq(op, "&&") ? a && b : eq(op, "|") ? a | b : eq(op, "^") ? a ^ b : eq(op, "&") ? a & b : eq(op, "==") ? a == b : eq(op, "!=") ? a != b : eq(op, "<") ? a < b : eq(op, ">") ? a > b : eq(op, "<=") ? a <= b : eq(op, ">=") ? a >= b : eq(op, "<<") ? a << b : eq(op, ">>") ? a >> b : eq(op, "+") ? a + b : eq(op, "-") ? a - b : eq(op, "*") ? a * b : eq(op, "/") ? a / b : eq(op, "%") ? a % b : diag("unrecognized operator '%s'", op); va_list args; va_start(args, fmt); vok_at_loc(file, line, test, fmt, args); va_end(args); if (!test) { diag(" %d", a); diag(" %s", op); diag(" %d", b); } return test; } static int find_mem_diff (const char *a, const char *b, size_t n, size_t *offset) { size_t i; if (a == b) return 0; if (!a || !b) return 2; for (i = 0; i < n; i++) { if (a[i] != b[i]) { *offset = i; return 1; } } return 0; } int cmp_mem_at_loc (const char *file, int line, const void *got, const void *expected, size_t n, const char *fmt, ...) { size_t offset; int diff = find_mem_diff(got, expected, n, &offset); va_list args; va_start(args, fmt); vok_at_loc(file, line, !diff, fmt, args); va_end(args); if (diff == 1) { diag(" Difference starts at offset %d", offset); diag(" got: 0x%02x", ((unsigned char *)got)[offset]); diag(" expected: 0x%02x", ((unsigned char *)expected)[offset]); } else if (diff == 2) { diag(" got: %s", got ? "not NULL" : "NULL"); diag(" expected: %s", expected ? "not NULL" : "NULL"); } return !diff; } int diag (const char *fmt, ...) { va_list args; char *mesg, *line; int i; va_start(args, fmt); if (!fmt) return 0; mesg = vstrdupf(fmt, args); line = mesg; for (i = 0; *line; i++) { char c = mesg[i]; if (!c || c == '\n') { mesg[i] = '\0'; printf("# %s\n", line); if (!c) break; mesg[i] = c; line = mesg + i + 1; } } free(mesg); va_end(args); return 0; } int exit_status () { int retval = 0; if (expected_tests == NO_PLAN) { printf("1..%d\n", current_test); } else if (current_test != expected_tests) { diag("Looks like you planned %d test%s but ran %d.", expected_tests, expected_tests > 1 ? "s" : "", current_test); retval = 2; } if (failed_tests) { diag("Looks like you failed %d test%s of %d run.", failed_tests, failed_tests > 1 ? "s" : "", current_test); retval = 1; } return retval; } int bail_out (int ignore, const char *fmt, ...) { va_list args; va_start(args, fmt); printf("Bail out! "); vprintf(fmt, args); printf("\n"); va_end(args); exit(255); return 0; } void tap_skip (int n, const char *fmt, ...) { char *why; va_list args; va_start(args, fmt); why = vstrdupf(fmt, args); va_end(args); while (n --> 0) { printf("ok %d ", ++current_test); diag("skip %s\n", why); } free(why); } void tap_todo (int ignore, const char *fmt, ...) { va_list args; va_start(args, fmt); todo_mesg = vstrdupf(fmt, args); va_end(args); } void tap_end_todo () { free(todo_mesg); todo_mesg = NULL; } #ifndef _WIN32 #include #include #include #if defined __APPLE__ || defined BSD #define MAP_ANONYMOUS MAP_ANON #endif /* Create a shared memory int to keep track of whether a piece of code executed dies. to be used in the dies_ok and lives_ok macros. */ int tap_test_died (int status) { static int *test_died = NULL; int prev; if (!test_died) { test_died = mmap(0, sizeof (int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); *test_died = 0; } prev = *test_died; *test_died = status; return prev; } int like_at_loc (int for_match, const char *file, int line, const char *got, const char *expected, const char *fmt, ...) { int test; regex_t re; va_list args; int err = regcomp(&re, expected, REG_EXTENDED); if (err) { char errbuf[256]; regerror(err, &re, errbuf, sizeof errbuf); fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n", expected, errbuf, file, line); exit(255); } err = regexec(&re, got, 0, NULL, 0); regfree(&re); test = for_match ? !err : err; va_start(args, fmt); vok_at_loc(file, line, test, fmt, args); va_end(args); if (!test) { if (for_match) { diag(" '%s'", got); diag(" doesn't match: '%s'", expected); } else { diag(" '%s'", got); diag(" matches: '%s'", expected); } } return test; } #endif powerman-2.4.4/src/libtap/tap.h000066400000000000000000000113721467035776500164000ustar00rootroot00000000000000/* libtap - Write tests in C Copyright 2012 Jake Gelbman This file is licensed under the LGPL */ #ifndef __TAP_H__ #define __TAP_H__ #ifdef __cplusplus extern "C" { #endif #ifndef va_copy #ifdef __va_copy #define va_copy __va_copy #else #define va_copy(d, s) ((d) = (s)) #endif #endif #include #include #include int vok_at_loc (const char *file, int line, int test, const char *fmt, va_list args); int ok_at_loc (const char *file, int line, int test, const char *fmt, ...); int is_at_loc (const char *file, int line, const char *got, const char *expected, const char *fmt, ...); int isnt_at_loc (const char *file, int line, const char *got, const char *expected, const char *fmt, ...); int cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b, const char *fmt, ...); int cmp_mem_at_loc (const char *file, int line, const void *got, const void *expected, size_t n, const char *fmt, ...); int bail_out (int ignore, const char *fmt, ...); void tap_plan (int tests, const char *fmt, ...); int diag (const char *fmt, ...); int exit_status (void); void tap_skip (int n, const char *fmt, ...); void tap_todo (int ignore, const char *fmt, ...); void tap_end_todo (void); #define NO_PLAN -1 #define SKIP_ALL -2 #define ok(...) ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) #define is(...) is_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) #define isnt(...) isnt_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) #define cmp_ok(...) cmp_ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) #define cmp_mem(...) cmp_mem_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL); #define plan(...) tap_plan(__VA_ARGS__, NULL) #define done_testing() return exit_status() #define BAIL_OUT(...) bail_out(0, "" __VA_ARGS__, NULL) #define pass(...) ok(1, "" __VA_ARGS__) #define fail(...) ok(0, "" __VA_ARGS__) #define skip(test, ...) do {if (test) {tap_skip(__VA_ARGS__, NULL); break;} #define end_skip } while (0) #define todo(...) tap_todo(0, "" __VA_ARGS__, NULL) #define end_todo tap_end_todo() #define dies_ok(...) dies_ok_common(1, __VA_ARGS__) #define lives_ok(...) dies_ok_common(0, __VA_ARGS__) #ifdef _WIN32 #define like(...) tap_skip(1, "like is not implemented on Windows") #define unlike tap_skip(1, "unlike is not implemented on Windows") #define dies_ok_common(...) \ tap_skip(1, "Death detection is not supported on Windows") #else #define like(...) like_at_loc(1, __FILE__, __LINE__, __VA_ARGS__, NULL) #define unlike(...) like_at_loc(0, __FILE__, __LINE__, __VA_ARGS__, NULL) int like_at_loc (int for_match, const char *file, int line, const char *got, const char *expected, const char *fmt, ...); #include #include #include int tap_test_died (int status); #define dies_ok_common(for_death, code, ...) \ do { \ int cpid; \ int it_died; \ tap_test_died(1); \ cpid = fork(); \ switch (cpid) { \ case -1: \ perror("fork error"); \ exit(1); \ case 0: \ close(1); \ close(2); \ code \ tap_test_died(0); \ exit(0); \ } \ if (waitpid(cpid, NULL, 0) < 0) { \ perror("waitpid error"); \ exit(1); \ } \ it_died = tap_test_died(0); \ if (!it_died) \ {code} \ ok(for_death ? it_died : !it_died, "" __VA_ARGS__); \ } while (0) #endif #ifdef __cplusplus } #endif #endif powerman-2.4.4/src/plmpower/000077500000000000000000000000001467035776500160315ustar00rootroot00000000000000powerman-2.4.4/src/plmpower/Makefile.am000066400000000000000000000003071467035776500200650ustar00rootroot00000000000000AM_CFLAGS = @WARNING_CFLAGS@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcommon sbin_PROGRAMS = plmpower plmpower_SOURCES = plmpower.c plmpower_LDADD = \ $(top_builddir)/src/libcommon/libcommon.la powerman-2.4.4/src/plmpower/plmpower.c000066400000000000000000000511551467035776500200510ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2007 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* plmpower.c - control Insteon/X10 devices via SmartLabs PLM 2412S */ /* References: * For PLM bits, see "Insteon Modem Developer's Guide", * http://www.smarthome.com/manuals/2412sdevguide.pdf * For general Insteon protocol, see "Insteon: The Details" * http://www.insteon.net/pdf/insteondetails.pdf * For Insteon commands, see "EZBridge Reference Manual", Appendix B. * http://www.simplehomenet.com/Downloads/EZBridge%20Manual.pdf * Also: "Quick Reference Guide for Smarthome Device Manager for INSTEON" * http://www.insteon.net/sdk/files/dm/docs/ */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "xmalloc.h" #include "error.h" #include "argv.h" #include "xread.h" #include "xtime.h" #include "xpoll.h" /* PLM commands */ #define IM_RECV_STD 0x50 /* plm -> host */ #define IM_RECV_EXT 0x51 #define IM_RECV_X10 0x52 #define IM_RECV_ALL_LINK_COMPLETE 0x53 #define IM_RECV_BUTTON 0x54 #define IM_RECV_RESET 0x55 #define IM_RECV_ALL_LINK_FAIL 0x56 #define IM_RECV_ALL_LINK_REC 0x57 #define IM_RECV_ALL_LINK_STAT 0x58 #define IM_GET_INFO 0x60 /* host -> plm */ #define IM_SEND_ALL_LINK 0x61 #define IM_SEND 0x62 #define IM_SEND_X10 0x63 #define IM_START_ALL_LINK 0x64 #define IM_CANCEL_ALL_LINK 0x65 #define IM_SET_HOST_CATEGORY 0x66 #define IM_RESET 0x67 #define IM_SET_ACK 0x68 #define IM_GET_FIRST_ALL_LINK_REC 0x69 #define IM_GET_NEXT_ALL_LINK_REC 0x6A #define IM_CONFIG_SET 0x6B #define IM_GET_SENDER_ALL_LINK_REC 0x6C #define IM_LED_ON 0x6D #define IM_LED_OFF 0x6E #define IM_MANAGE_ALL_LINK_REC 0x6F #define IM_SET_NACK 0x70 #define IM_SET_ACK2 0x71 #define IM_RF_SLEEP 0x72 #define IM_CONFIG_GET 0x73 /* PLM control bytes */ #define IM_STX 0x02 #define IM_ACK 0x06 #define IM_NAK 0x15 /* PLM config bits */ #define IM_CONFIG_BUTLINK_DISABLE 0x80 #define IM_CONFIG_MONITOR_MODE 0x40 #define IM_CONFIG_AUTOLED_DISABLE 0x20 #define IM_CONFIG_DEADMAN_DISABLE 0x10 #define IM_MAX_RECVLEN 28 /* response to send extended msg */ /* Insteon commands (incomplete) */ #define CMD_GRP_ASSIGN 0x01 #define CMD_GRP_DELETE 0x02 #define CMD_PING 0x10 #define CMD_ON 0x11 #define CMD_ON_FAST 0x12 #define CMD_OFF 0x13 #define CMD_OFF_FAST 0x14 #define CMD_BRIGHT 0x15 #define CMD_DIM 0x16 #define CMD_MAN_START 0x17 #define CMD_MAN_STOP 0x18 #define CMD_STATUS 0x19 /* X10 commands */ #define X10_ALL_UNITS_OFF 0x0 #define X10_ALL_LIGHTS_ON 0x1 #define X10_ON 0x2 #define X10_OFF 0x3 #define X10_DIM 0x4 #define X10_BRIGHT 0x5 #define X10_ALL_LIGHTS_OFF 0x6 #define X10_EXT_CODE 0x7 #define X10_HAIL_REQ 0x8 #define X10_HAIL_ACK 0x9 #define X10_PRESET_DIM 0xa #define X10_PRESET_DIM2 0xb #define X10_EXT_DATA 0xc #define X10_STATUS_ON 0xd #define X10_STATUS_OFF 0xe #define X10_STATUS_REQ 0xf /* X10 encoding of housecode A-P and device code 1-16 */ static const int x10_enc[] = { 0x6, 0xe, 0x2, 0xa, 0x1, 0x9, 0x5, 0xd, 0x7, 0xf, 0x3, 0xb, 0x0, 0x8, 0x4, 0xc }; typedef struct { char h; char m; char l; } insaddr_t; typedef struct { char house; char unit; } x10addr_t; static void usage(void); static int open_serial(char *dev); static int run_cmd(int fd, char *cmd); static void shell(int fd); static void docmd(int fd, char **av, int *quitp); static void help(void); static void plm_reset(int fd); static void plm_info(int fd); static void plm_on(int fd, char *addrstr); static void plm_off(int fd, char *addrstr); static void plm_status(int fd, char *addrstr); static void plm_ping(int fd, char *addrstr); static int str2insaddr(char *s, insaddr_t *ip); static char *insaddr2str(insaddr_t *ip); static int str2x10addr(char *s, x10addr_t *xp); static int wait_until_ready(int fd, int timeout_msec); static int plm_recv(int fd, char cmd, char *recv, int recvlen); static void plm_docmd(int fd, char *send, int sendlen, char *recv, int recvlen); static void plm_send_insteon(int fd, insaddr_t *ip, char cmd1, char cmd2); static int plm_recv_insteon(int fd, insaddr_t *ip, char *cmd1, char *cmd2, int timeout_msec); static void plm_send_x10(int fd, x10addr_t *xp, char cmd); static int testmode = 0; static char test_plug = 0; static unsigned long x10_attempts = 3; static int insteon_tmout = 1000; /* (msec) */ #define OPTIONS "d:Tx:t:S:" static struct option longopts[] = { { "device", required_argument, 0, 'd' }, { "testmode", no_argument, 0, 'T' }, { "x10-attempts", required_argument, 0, 'x' }, { "timeout", required_argument, 0, 't' }, { "single-cmd", required_argument, 0, 'S' }, {0,0,0,0}, }; int main(int argc, char *argv[]) { char *device = NULL; int c; int fd = -1; char *single_cmd = NULL; err_init(basename(argv[0])); while ((c = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != EOF) { switch (c) { case 'd': /* --device */ device = optarg; break; case 'T': /* --testmode */ testmode = 1; break; case 't': /* --timeout */ insteon_tmout = strtoul(optarg, NULL, 10); if (insteon_tmout < 1) err_exit(false, "timeout must be >= 1 msec"); break; case 'x': /* --x10-attempts */ x10_attempts = strtoul(optarg, NULL, 10); if (x10_attempts < 1) err_exit(false, "X10 attempts must be >= 1"); break; case 'S': /* --single-cmd */ single_cmd = strdup(optarg); break; default: usage(); break; } } if (optind < argc) usage(); if (!testmode) { if (device == NULL) usage(); fd = open_serial(device); } if (single_cmd) { run_cmd(fd, single_cmd); free(single_cmd); } else shell(fd); if (close(fd) < 0) err_exit(true, "error closing %s", device); exit(0); } static void usage(void) { fprintf(stderr, "Usage: plmpower -d device \n"); exit(1); } /* Open the PLM's serial device [dev], lock it in a manner consistent * with powerman and conman, set baud rate, line discipline, etc, * and return file descriptor. */ static int open_serial(char *dev) { struct termios tio; int fd; fd = open(dev, O_RDWR | O_NOCTTY); if (fd < 0) err_exit(true, "could not open %s", dev); if (lockf(fd, F_TLOCK, 0) < 0) err_exit(true, "could not lock %s", dev); tcgetattr(fd, &tio); tio.c_cflag = B19200 | CS8 | CLOCAL | CREAD; tio.c_iflag = IGNBRK | IGNPAR; tio.c_oflag = ONLRET; tio.c_lflag = 0; tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 1; tcsetattr(fd, TCSANOW, &tio); return fd; } /* Parse the command line into an argv array which is passed to docmd() for * execution against PLM on [fd]. Returns if the user wants to quit. */ static int run_cmd(int fd, char *cmd) { int quit = 0; char **av; av = argv_create(cmd, ""); docmd(fd, av, &quit); argv_destroy(av); return (quit); } /* Prompt the user and run the command entered. * Returns when the user wants to quit. */ static void shell(int fd) { char buf[128]; int quit = 0; while (!quit) { printf("plmpower> "); fflush(stdout); if (fgets(buf, sizeof(buf), stdin)) { quit = run_cmd(fd, buf); } else quit = 1; } } /* Parse argv array [av] and execute any commands against PLM on [fd]. * If the user wants to quit, set [*quitp] to 1. */ static void docmd(int fd, char **av, int *quitp) { if (av[0] != NULL) { if (strcmp(av[0], "help") == 0) { help(); } else if (strcmp(av[0], "quit") == 0) { *quitp = 1; } else if (strcmp(av[0], "info") == 0) { if (testmode) printf("Unavailable in test mode\n"); else plm_info(fd); } else if (strcmp(av[0], "reset") == 0) { if (testmode) printf("Unavailable in test mode\n"); else plm_reset(fd); } else if (strcmp(av[0], "on") == 0) { if (argv_length(av) != 2) printf("Usage: on addr\n"); else plm_on(fd, av[1]); } else if (strcmp(av[0], "off") == 0) { if (argv_length(av) != 2) printf("Usage: off addr\n"); else plm_off(fd, av[1]); } else if (strcmp(av[0], "status") == 0) { if (argv_length(av) != 2) printf("Usage: status addr\n"); else plm_status(fd, av[1]); } else if (strcmp(av[0], "ping") == 0) { if (testmode) printf("Unavailable in test mode\n"); else if (argv_length(av) != 2) printf("Usage: ping addr\n"); else plm_ping(fd, av[1]); } else printf("type \"help\" for a list of commands\n"); } } /* Summarize interactive "shell" commands. */ static void help(void) { printf("Valid commands are:\n"); printf(" info get PLM info\n"); printf(" reset reset the PLM (clears all-link db)\n"); printf(" on addr turn on device\n"); printf(" off addr turn on device\n"); printf(" status addr query status of device\n"); printf(" ping addr time round trip request/response to device\n"); printf("Where addr is Insteon (e.g. 1A.2B.3C) or X10 (e.g. G12)\n"); } /* Send the ON command to [addrstr], either X10 or Insteon, via PLM on [fd]. * If Insteon, retry the command until a response is received. * If X10, send it x10_attempts times whether we need to or not. */ static void plm_on(int fd, char *addrstr) { insaddr_t i; x10addr_t x; char cmd2; if (str2insaddr(addrstr, &i)) { if (testmode) { test_plug = 1; } else { do { plm_send_insteon(fd, &i, CMD_ON_FAST, 0xff); } while (!plm_recv_insteon(fd, &i, NULL, &cmd2, insteon_tmout)); if (cmd2 == 0) err_exit(false, "on command failed"); } } else if (str2x10addr(addrstr, &x)) { if (!testmode) plm_send_x10(fd, &x, X10_ON); } else err(false, "could not parse address"); } /* Send the OFF command to [addrstr], either X10 or Insteon, via PLM on [fd]. * If Insteon, retry the command until a response is received. * If X10, send it x10_attempts times whether we need to or not. */ static void plm_off(int fd, char *addrstr) { insaddr_t i; x10addr_t x; char cmd2; if (str2insaddr(addrstr, &i)) { if (testmode) { test_plug = 0; } else { do { plm_send_insteon(fd, &i, CMD_OFF_FAST, 0); } while (!plm_recv_insteon(fd, &i, NULL, &cmd2, insteon_tmout)); if (cmd2 != 0) err_exit(false, "off command failed"); } } else if (str2x10addr(addrstr, &x)) { if (!testmode) plm_send_x10(fd, &x, X10_OFF); } else err(false, "could not parse address"); } /* Send the Insteon STATUS command to [addrstr] via PLM on [fd] and print * the result on stdout. Retry the command until a response is received. * X10 addresses are accepted here, but we always report status as "unknown". */ static void plm_status(int fd, char *addrstr) { insaddr_t i; x10addr_t x; char cmd2; if (str2insaddr(addrstr, &i)) { if (testmode) { cmd2 = test_plug; } else { do { plm_send_insteon(fd, &i, CMD_STATUS, 0); } while (!plm_recv_insteon(fd, &i, NULL, &cmd2, insteon_tmout)); } printf("%s: %.2hhX\n", addrstr, cmd2); } else if (str2x10addr(addrstr, &x)) printf("%s: unknown\n", addrstr); else err(false, "could not parse address"); } /* Send the Insteon PING command to [addrstr] via PLM on [fd] * and print the round-trip time and number of retries on stdout. * Retry the command until a response is received. */ static void plm_ping(int fd, char *addrstr) { insaddr_t i; x10addr_t x; struct timeval t1, t2, delta; int tries = 0; /* FIXME: make this work more like ping(8). */ if (str2insaddr(addrstr, &i)) { if (gettimeofday(&t1, NULL) < 0) err_exit(true, "gettimeofday"); do { tries++; plm_send_insteon(fd, &i, CMD_PING, 0); } while (!plm_recv_insteon(fd, &i, NULL, NULL, insteon_tmout)); if (gettimeofday(&t2, NULL) < 0) err_exit(true, "gettimeofday"); timersub(&t2, &t1, &delta); printf("PING from %s: retries=%d time=%.2lf ms\n", addrstr, tries - 1, (double)delta.tv_usec / 1000.0 + (double)delta.tv_sec * 1000.0); } else if (str2x10addr(addrstr, &x)) err(false, "ping is only for Insteon devices"); else err(false, "could not parse address"); } /* Convert a string [s] to Insteon address [ip]. * Return 1 on success, 0 on failure. */ static int str2insaddr(char *s, insaddr_t *ip) { if (sscanf(s, "%2hhx.%2hhx.%2hhx", &ip->h, &ip->m, &ip->l) != 3) return 0; return 1; } /* Convert an Insteon address [ip] to string [returned]. * Returns pointer to static data overwritten on each call. */ static char * insaddr2str(insaddr_t *ip) { static char s[64]; snprintf(s, sizeof(s), "%.2hhX.%.2hhX.%.2hhX", ip->h, ip->m, ip->l); return s; } /* Convert a string [s] to X10 address [xp]. * Return 1 on success, 0 on failure. */ static int str2x10addr(char *s, x10addr_t *xp) { unsigned long i; if (isupper(s[0])) s[0] = tolower(s[0]); if (!islower(s[0]) || s[0] > 'p') return 0; xp->house = x10_enc[s[0] - 'a']; i = strtoul(&s[1], NULL, 10) - 1; if (i >= sizeof(x10_enc)/sizeof(int)) return 0; xp->unit = x10_enc[i]; return 1; } /* Wait until PLM on [fd] has data ready for reading or [timeout_msec] expires. * Return value is 1 on data ready, 0 on timeout. */ static int wait_until_ready(int fd, int timeout_msec) { struct timeval tv = { timeout_msec / 1000, (timeout_msec % 1000) * 1000 }; xpollfd_t pfd = xpollfd_create(); int res = 1; xpollfd_set(pfd, fd, XPOLLIN); if (xpoll(pfd, &tv) == 0) res = 0; xpollfd_destroy(pfd); return res; } /* Receive a command or a response from the PLM on [fd] and return it * in [recv] of length [recvlen]. If the a command is received which does * not match [cmd], silently discard it. If a NAK is received instead of STX * indicating the PLM was busy when the last command was sent, return 1, * otherwise return 0. */ static int plm_recv(int fd, char cmd, char *recv, int recvlen) { char b[IM_MAX_RECVLEN]; retry: xread_all(fd, &b[0], 1); if (b[0] == IM_NAK) return 1; else if (b[0] != IM_STX) err_exit(false, "expected IM_STX or IM_NAK, got %.2hhX", b[0]); xread_all(fd, &b[1], 1); if (b[1] != cmd) { switch (b[1]) { case IM_RECV_STD: xread_all(fd, &b[2], 9); break; case IM_RECV_EXT: xread_all(fd, &b[2], 23); break; case IM_RECV_X10: xread_all(fd, &b[2], 2); break; case IM_RECV_ALL_LINK_COMPLETE: xread_all(fd, &b[2], 8); break; case IM_RECV_BUTTON: xread_all(fd, &b[2], 1); break; case IM_RECV_RESET: break; case IM_RECV_ALL_LINK_FAIL: xread_all(fd, &b[2], 5); break; case IM_RECV_ALL_LINK_REC: xread_all(fd, &b[2], 8); break; case IM_RECV_ALL_LINK_STAT: xread_all(fd, &b[2], 1); break; default: err_exit(false, "unexpected command: %.2hhX", b[1]); break; } goto retry; } xread_all(fd, &b[2], recvlen - 2); memcpy(recv, b, recvlen); return 0; } /* Send a command [send] of length [sendlen] to PLM on [fd], then * read the response into [recv] of length [recvlen]. If a NAK is * received, retry the command until it is ACKed. */ static void plm_docmd(int fd, char *send, int sendlen, char *recv, int recvlen) { int nak; do { xwrite_all(fd, send, sendlen); nak = plm_recv(fd, send[1], recv, recvlen); if (!nak && recv[recvlen - 1] == IM_NAK) nak = 1; /* FIXME: retry appropriate here or is command broken? */ if (nak) usleep(1000*100); /* wait 100ms for PLM to become ready */ } while (nak); } /* Send IM_RESET to the PLM on [fd]. */ static void plm_reset(int fd) { char send[2] = { IM_STX, IM_RESET }; char recv[3]; plm_docmd(fd, send, sizeof(send), recv, sizeof(recv)); printf("PLM reset complete\n"); } /* Send IM_GET_INFO to the PLM on [fd] and print the response on stdout. */ static void plm_info(int fd) { insaddr_t i; char send[2] = { IM_STX, IM_GET_INFO }; char recv[9]; plm_docmd(fd, send, sizeof(send), recv, sizeof(recv)); i.h = recv[2]; i.m = recv[3]; i.l = recv[4]; printf("id=%s dev=%.2hhX.%.2hhX vers=%hhd\n", insaddr2str(&i), recv[5], recv[6], recv[7]); } /* Send an Insteon command described by [cmd1] and [cmd2] to address [ip] * using PLM on [fd]. The command will be retried until accepted by the PLM. */ static void plm_send_insteon(int fd, insaddr_t *ip, char cmd1, char cmd2) { char send[8] = { IM_STX, IM_SEND, ip->h, ip->m, ip->l, 3, cmd1, cmd2 }; char recv[9]; plm_docmd(fd, send, sizeof(send), recv, sizeof(recv)); } /* Receive an Insteon command from address [i] into [cmd1] and [cmd2] * via PLM on [fd]. If more than [timeout_msec] milliseconds elapses, * give up and return 0, else return 1. */ static int plm_recv_insteon(int fd, insaddr_t *ip, char *cmd1, char *cmd2, int timeout_msec) { char recv[11]; int nak; do { /* FIXME: timeout is restarted if an unsolicited command is received */ if (!wait_until_ready(fd, timeout_msec)) return 0; nak = plm_recv(fd, IM_RECV_STD, recv, sizeof(recv)); if (nak) err_exit(false, "unexpected NAK while waiting for Insteon packet"); } while (ip->h != recv[2] || ip->m != recv[3] || ip->l != recv[4]); if (cmd1) *cmd1 = recv[9]; if (cmd2) *cmd2 = recv[10]; return 1; } /* Send an X10 command [cmd] to address [xp] via PLM on [fd]. * Repeat the command x10_attempts times for good measure because we will * get no acknowledgement from the device. */ static void plm_send_x10(int fd, x10addr_t *xp, char cmd) { char senda[4] = { IM_STX, IM_SEND_X10, (xp->house << 4) | xp->unit, 0 }; char sendb[4] = { IM_STX, IM_SEND_X10, (xp->house << 4) | cmd, 0x80 }; char recv[5]; int i; for (i = 0; i < x10_attempts; i++) { plm_docmd(fd, senda, sizeof(senda), recv, sizeof(recv)); plm_docmd(fd, sendb, sizeof(sendb), recv, sizeof(recv)); } } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/000077500000000000000000000000001467035776500160145ustar00rootroot00000000000000powerman-2.4.4/src/powerman/.gitignore000066400000000000000000000001071467035776500200020ustar00rootroot00000000000000/parse_lex.c /parse_tab.c /parse_tab.h /test_* /pm /powerman /powrmand powerman-2.4.4/src/powerman/Makefile.am000066400000000000000000000026341467035776500200550ustar00rootroot00000000000000AM_CFLAGS = @WARNING_CFLAGS@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/liblsd \ -I$(top_srcdir)/src/libcommon bin_PROGRAMS = \ powerman \ pm$(EXEEXT) sbin_PROGRAMS = \ powermand lib_LTLIBRARIES = \ libpowerman.la include_HEADERS = \ libpowerman.h powerman_SOURCES = \ powerman.c powerman_LDADD = \ $(top_builddir)/src/liblsd/liblsd.la \ $(top_builddir)/src/libcommon/libcommon.la \ $(LIBGENDERS) pm_SOURCES = pm$(EXEEXT): powerman rm -f $@ $(LN_S) $< $@ powermand_SOURCES = \ arglist.c \ arglist.h \ client.c \ client.h \ client_proto.h \ debug.c \ debug.h \ device.c \ device.h \ device_pipe.c \ device_pipe.h \ device_private.h \ device_serial.c \ device_serial.h \ device_tcp.c \ device_tcp.h \ parse_lex.l \ parse_tab.y \ parse_util.c \ parse_util.h \ pluglist.c \ pluglist.h \ powerman.h \ powermand.c powermand_LDADD = \ $(top_builddir)/src/liblsd/liblsd.la \ $(top_builddir)/src/libcommon/libcommon.la \ $(LIBWRAP) AM_YFLAGS = -d parse_lex.c : parse_tab.h CLEANFILES = \ parse_lex.c \ parse_tab.c \ parse_tab.h libpowerman_la_SOURCES = \ libpowerman.c check_PROGRAMS = \ test_pluglist \ test_apiclient test_pluglist_SOURCES = test/pluglist.c test_pluglist_LDADD = \ $(builddir)/pluglist.o \ $(top_builddir)/src/libcommon/libcommon.la \ $(top_builddir)/src/liblsd/liblsd.la test_apiclient_SOURCES = test/apiclient.c test_apiclient_LDADD = \ $(builddir)/libpowerman.la powerman-2.4.4/src/powerman/arglist.c000066400000000000000000000070221467035776500176260ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* Args used to be stored in a List, but gprof showed that very large * configurations spent a lot of time doing linear search of arg list for * each arg->state update. The List was traded for a hash, but as we still * want to iterate through args in the client in order, we keep the hostlist * representation of the nodes in the ArgList, and use it to implement an * 'iterator' interface. */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include "list.h" #include "xmalloc.h" #include "hostlist.h" #include "hash.h" #include "arglist.h" struct arglist_iterator { hostlist_iterator_t itr; ArgList arglist; }; struct arglist { hash_t args; hostlist_t hl; int refcount; /* free when refcount == 0 */ }; static void _destroy_arg(Arg * arg) { assert(arg != NULL); assert(arg->node != NULL); xfree(arg->node); if (arg->val) xfree(arg->val); xfree(arg); } static Arg *_create_arg(char *node) { Arg *arg = (Arg *) xmalloc(sizeof(Arg)); arg->node = xstrdup(node); arg->state = ST_UNKNOWN; arg->val = NULL; return arg; } ArgList arglist_create(hostlist_t hl) { ArgList new = (ArgList) xmalloc(sizeof(struct arglist)); hostlist_iterator_t itr; char *node; int hash_size; new->refcount = 1; hash_size = hostlist_count(hl); /* reasonable? */ new->args = hash_create(hash_size, (hash_key_f)hash_key_string, (hash_cmp_f)strcmp, (hash_del_f)_destroy_arg); if ((itr = hostlist_iterator_create(hl)) == NULL) { arglist_unlink(new); return NULL; } while ((node = hostlist_next(itr)) != NULL) { Arg *arg = _create_arg(node); hash_insert(new->args, arg->node, arg); free(node); /* hostlist_next strdups returned string */ } hostlist_iterator_destroy(itr); new->hl = hostlist_copy(hl); return new; } void arglist_unlink(ArgList arglist) { if (--arglist->refcount == 0) { hash_destroy(arglist->args); hostlist_destroy(arglist->hl); xfree(arglist); } } ArgList arglist_link(ArgList arglist) { arglist->refcount++; return arglist; } Arg *arglist_find(ArgList arglist, char *node) { Arg *arg = NULL; if (node != NULL) arg = hash_find(arglist->args, node); return arg; } ArgListIterator arglist_iterator_create(ArgList arglist) { ArgListIterator itr = (ArgListIterator)xmalloc(sizeof(struct arglist_iterator)); itr->arglist = arglist; itr->itr = hostlist_iterator_create(arglist->hl); return itr; } void arglist_iterator_destroy(ArgListIterator itr) { hostlist_iterator_destroy(itr->itr); xfree(itr); } Arg *arglist_next(ArgListIterator itr) { Arg *arg = NULL; char *node; node = hostlist_next(itr->itr); if (node != NULL) { arg = hash_find(itr->arglist->args, node); free(node); /* hostlist_next strdups returned string */ } return arg; } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/arglist.h000066400000000000000000000040551467035776500176360ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* * The ArgList is used to pass the list of "target nodes" into a device * script, and then to pass the result back to the client. */ #ifndef PM_ARGLIST_H #define PM_ARGLIST_H typedef enum { ST_UNKNOWN, ST_OFF, ST_ON } InterpState; /* result not required to be set after power operation, * result defaults to RT_NONE in that case. */ typedef enum { RT_NONE, RT_UNKNOWN, RT_SUCCESS } InterpResult; typedef struct { char *node; /* node name (in) */ char *val; /* value as returned by the device (out) */ InterpState state; /* interpreted value, if appropriate (out) */ InterpResult result; /* interpreted result, if appropriate (out) */ } Arg; typedef struct arglist_iterator *ArgListIterator; typedef struct arglist *ArgList; /* Create an ArgList with an Arg entry for each node in hl (refcount == 1). */ ArgList arglist_create(hostlist_t hl); /* Do refcount++ in ArgList. */ ArgList arglist_link(ArgList arglist); /* Do refcount-- in ArgList. * If the refcount reaches zero, destroy the Arglist. */ void arglist_unlink(ArgList arglist); /* Search ArgList for an Arg entry that matches node. * Return pointer to Arg on success (points to actual list entry), * or NULL on search failure. */ Arg * arglist_find(ArgList arglist, char *node); /* An iterator interface for ArgLists, similar to the iterators in list.h. */ ArgListIterator arglist_iterator_create(ArgList arglist); void arglist_iterator_destroy(ArgListIterator itr); Arg * arglist_next(ArgListIterator itr); #endif /* PM_ARGLIST_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/client.c000066400000000000000000001057261467035776500174510ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* This is the component of the server that deals with clients. * The client itself is contained in powerman.c. */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_TCP_WRAPPERS #include #endif #include #include #include "xmalloc.h" #include "xpoll.h" #include "xregex.h" #include "hostlist.h" #include "list.h" #include "parse_util.h" #include "client.h" #include "cbuf.h" #include "error.h" #include "client_proto.h" #include "debug.h" #include "pluglist.h" #include "hprintf.h" #include "arglist.h" #include "device_private.h" #include "fdutil.h" #include "powerman.h" #ifndef HAVE_SOCKLEN_T typedef int socklen_t; /* socklen_t is uint32_t in Posix.1g */ #endif /* !HAVE_SOCKLEN_T */ #define LISTEN_BACKLOG 5 #define MIN_CLIENT_BUF 1024 #define MAX_CLIENT_BUF 1024*1024 typedef struct { int com; /* script index */ hostlist_t hl; /* target nodes */ int pending; /* count of pending device actions */ bool error; /* cumulative error flag for actions */ ArgList arglist; /* argument for query commands */ } Command; typedef struct { int fd; /* file descriptor for the socket */ int ofd; /* separate output file descriptor (if used) */ char *ip; /* IP address of the client's host */ unsigned short int port; /* Port of client connection */ char *host; /* host name of client host */ cbuf_t to; /* out buffer */ cbuf_t from; /* in buffer */ Command *cmd; /* command (there can be only one) */ int client_id; /* client identifier */ bool telemetry; /* client wants telemetry debugging info */ bool exprange; /* client wants host ranges expanded */ bool client_quit; /* set true after client quit command */ } Client; /* prototypes for internal functions */ static Command *_create_command(Client * c, int com, char *arg1); static void _destroy_command(Command * cmd); static int _match_client(Client * c, void *key); static Client *_find_client(int client_id); static hostlist_t _hostlist_create_validated(Client * c, char *str); static void _client_query_nodes_reply(Client * c); static void _client_query_device_reply(Client * c, char *arg); static void _client_query_status_reply(Client * c, bool error); static void _client_query_status_reply_nointerp(Client * c, bool error); static void _handle_read(Client * c); static void _handle_write(Client * c); static void _handle_input(Client *c); static char *_strip_whitespace(char *str); static void _parse_input(Client * c, char *input); static void _destroy_client(Client * c); static void _create_client_socket(int fd); static void _create_client_stdio(void); static void _act_finish(int client_id, ActError acterr, const char *fmt, ...); static void _telemetry_printf(int client_id, const char *fmt, ...); static void _diag_printf(int client_id, const char *fmt, ...); #if HAVE_TCP_WRAPPERS /* tcp wrappers support */ extern int hosts_ctl(char *daemon, char *client_name, char *client_addr, char *client_user); int allow_severity = LOG_INFO; /* logging level for accepted reqs */ int deny_severity = LOG_WARNING;/* logging level for rejected reqs */ #endif static int *listen_fds; /* powermand listen sockets */ static int listen_fds_len = 0; /* count of above sockets */ static List cli_clients = NULL; /* list of clients */ static bool one_client = false; /* terminate after first client */ static bool server_done = false;/* true when stdio client exits */ static int cli_id_seq = 1; /* range 1...INT_MAX */ #define _next_cli_id() \ (cli_id_seq < INT_MAX ? cli_id_seq++ : (cli_id_seq = 1, INT_MAX)) #define _internal_error_response(c) \ _client_printf(c, CP_ERR_INTERNAL, __FILE__, __LINE__) #include "hostlist.h" /* * Wrapped hostlist_ranged_string() with internal buffer allocation, * which caller must xfree(). */ #define CHUNKSIZE 80 static char *_xhostlist_ranged_string(hostlist_t hl) { int size = 0; char *str = NULL; do { str = (size == 0) ? xmalloc(CHUNKSIZE) : xrealloc(str, size+CHUNKSIZE); size += CHUNKSIZE; } while (hostlist_ranged_string(hl, size, str) == -1); return str; } /* * printf-like function which writes to the output cbuf. */ static void _client_printf(Client *c, const char *fmt, ...) { char *str = NULL; int written, dropped; va_list ap; va_start(ap, fmt); str = hvsprintf(fmt, ap); va_end(ap); /* Write to the client buffer */ written = cbuf_write(c->to, str, strlen(str), &dropped); if (written < 0) err(true, "_client_printf: cbuf_write returned %d", written); else if (dropped > 0) err(false, "_client_printf: cbuf_write dropped %d chars", dropped); /* Free the tmp string */ xfree(str); } /* * Initialize module. */ void cli_init(void) { /* create cli_clients list */ cli_clients = list_create((ListDelF) _destroy_client); } /* * Finalize module. */ void cli_fini(void) { /* destroy clients */ list_destroy(cli_clients); } /* * Build a hostlist_t from a string, validating each node name against * powerman configuration. If any bogus nodes are found, issue error * response to client and return NULL. */ static hostlist_t _hostlist_create_validated(Client * c, char *str) { hostlist_t hl = NULL; hostlist_t badhl = NULL; hostlist_iterator_t itr = NULL; char *host; bool valid = true; if ((hl = hostlist_create(str)) == NULL) { /* Note: report detailed error since 'str' comes from the user */ if (errno == ERANGE || errno == EINVAL) _client_printf(c, CP_ERR_HOSTLIST, "invalid range"); else _internal_error_response(c); return NULL; } conf_exp_aliases(hl); if ((badhl = hostlist_create(NULL)) == NULL) { /* Note: other hostlist failures not user-induced so OK to be vague */ _internal_error_response(c); return NULL; } if ((itr = hostlist_iterator_create(hl)) == NULL) { _internal_error_response(c); hostlist_destroy(hl); return NULL; } while ((host = hostlist_next(itr)) != NULL) { if (!conf_node_exists(host)) { valid = false; hostlist_push_host(badhl, host); } free(host); /* hostlist_next strdups returned string */ } if (!valid) { char *hosts; hosts = _xhostlist_ranged_string(badhl); _client_printf(c, CP_ERR_NOSUCHNODES, hosts); xfree (hosts); hostlist_iterator_destroy(itr); hostlist_destroy(hl); hostlist_destroy(badhl); return NULL; } hostlist_iterator_destroy(itr); hostlist_destroy(badhl); return hl; } /* * Reply to client request for list of nodes in powerman configuration. */ static void _client_query_nodes_reply(Client * c) { hostlist_t nodes = conf_getnodes(); hostlist_sort(nodes); if (c->exprange) { hostlist_iterator_t itr; char *node; if ((itr = hostlist_iterator_create(nodes)) == NULL) { _internal_error_response(c); return; } while ((node = hostlist_next(itr))) { _client_printf(c, CP_INFO_XNODES, node); free(node); /* hostlist_next strdups returned string */ } hostlist_iterator_destroy(itr); } else { char *hosts = _xhostlist_ranged_string(nodes); _client_printf(c, CP_INFO_NODES, hosts); xfree (hosts); } _client_printf(c, CP_RSP_QRY_COMPLETE); } /* * Helper for _client_query_device_reply() . * Create a hostlist string for the nodes attached to the specified device. * Caller must xfree(). */ static char *_make_pluglist_str(Device * dev) { hostlist_t hl = hostlist_create(NULL); PlugListIterator itr; Plug *plug; char *str = NULL; if (hl) { itr = pluglist_iterator_create(dev->plugs); while ((plug = pluglist_next(itr))) { assert(plug->name != NULL); hostlist_push(hl, plug->node); } pluglist_iterator_destroy(itr); hostlist_sort(hl); str = _xhostlist_ranged_string(hl); hostlist_destroy(hl); } return str; } /* * Helper for _client_query_device_reply. * Return true if hostlist string in 'arg' matches any plugs on device. */ static bool _device_matches_targets(Device *dev, char *arg) { hostlist_t targ = hostlist_create(arg); PlugListIterator itr; Plug *plug; bool res = false; if (targ != NULL) { itr = pluglist_iterator_create(dev->plugs); while ((plug = pluglist_next(itr))) { if (hostlist_find(targ, plug->node) != -1) { res = true; break; } } pluglist_iterator_destroy(itr); hostlist_destroy(targ); } return res; } /* * Reply to client request for list of devices in powerman configuration. */ static void _client_query_device_reply(Client * c, char *arg) { List devs = dev_getdevices(); Device *dev; ListIterator itr; if (devs) { itr = list_iterator_create(devs); while ((dev = list_next(itr))) { char *nodelist; int con = dev->stat_successful_connects; if (arg && !_device_matches_targets(dev, arg)) continue; if ((nodelist = _make_pluglist_str(dev))) { _client_printf(c, CP_INFO_DEVICE, dev->name, dev->connect_state == DEV_CONNECTED ? "connected" : dev->connect_state == DEV_CONNECTING ? "connecting" : "disconnected", con > 0 ? con - 1 : 0, dev->stat_successful_actions, dev->specname, nodelist); xfree (nodelist); } } list_iterator_destroy(itr); } _client_printf(c, CP_RSP_QRY_COMPLETE); } /* * Reply to client power command (on/off/cycle/reset/beacon on/beacon off) */ static void _client_power_status_reply(Client * c, bool error) { Arg *arg; ArgListIterator itr; int error_found = 0; assert(c->cmd != NULL); /* N.B. if result is RT_NONE, device script does not * specify setresult interpretation. */ itr = arglist_iterator_create(c->cmd->arglist); while ((arg = arglist_next(itr))) { if (arg->result == RT_UNKNOWN) { error_found++; break; } } arglist_iterator_destroy(itr); if (c->cmd->error || error_found) _client_printf(c, CP_ERR_COM_COMPLETE); else _client_printf(c, CP_RSP_COM_COMPLETE); } /* * Reply to client request for plug/soft status. */ static void _client_query_status_reply(Client * c, bool error) { Arg *arg; ArgListIterator itr; assert(c->cmd != NULL); if (c->exprange) { itr = arglist_iterator_create(c->cmd->arglist); while ((arg = arglist_next(itr))) { _client_printf(c, CP_INFO_XSTATUS, arg->node, arg->state == ST_ON ? "on" : arg->state == ST_OFF ? "off" : "unknown"); } arglist_iterator_destroy(itr); } else { char *on, *off, *unknown; hostlist_t hl_on, hl_off, hl_unknown; hl_on = hostlist_create(NULL); hl_off = hostlist_create(NULL); hl_unknown = hostlist_create(NULL); itr = arglist_iterator_create(c->cmd->arglist); while ((arg = arglist_next(itr))) { switch (arg->state) { case ST_UNKNOWN: hostlist_push(hl_unknown, arg->node); break; case ST_ON: hostlist_push(hl_on, arg->node); break; case ST_OFF: hostlist_push(hl_off, arg->node); break; } } arglist_iterator_destroy(itr); hostlist_sort(hl_unknown); hostlist_sort(hl_on); hostlist_sort(hl_off); unknown = _xhostlist_ranged_string(hl_unknown); on = _xhostlist_ranged_string(hl_on); off = _xhostlist_ranged_string(hl_off); hostlist_destroy(hl_unknown); hostlist_destroy(hl_on); hostlist_destroy(hl_off); _client_printf(c, CP_INFO_STATUS, on, off, unknown); xfree (unknown); xfree (on); xfree (off); } if (error) _client_printf(c, CP_ERR_QRY_COMPLETE); else _client_printf(c, CP_RSP_QRY_COMPLETE); } /* * Reply to client request for temperature/beacon status. */ static void _client_query_status_reply_nointerp(Client * c, bool error) { Arg *arg; ArgListIterator itr; hostlist_t hl = hostlist_create(NULL); char *tmpstr; assert(c->cmd != NULL); itr = arglist_iterator_create(c->cmd->arglist); while ((arg = arglist_next(itr))) { _client_printf(c, CP_INFO_XSTATUS, arg->node, arg->val); if (!arg->val) hostlist_push(hl, arg->node); } arglist_iterator_destroy(itr); if (!hostlist_is_empty(hl)) { hostlist_sort(hl); tmpstr = _xhostlist_ranged_string(hl); _client_printf(c, CP_INFO_XSTATUS, tmpstr, "unknown"); xfree (tmpstr); } if (error) _client_printf(c, CP_ERR_QRY_COMPLETE); else _client_printf(c, CP_RSP_QRY_COMPLETE); hostlist_destroy(hl); } /* * Create Command. * On error, return an error to the client and NULL to the caller. */ static Command *_create_command(Client * c, int com, char *arg1) { Command *cmd = (Command *) xmalloc(sizeof(Command)); cmd->com = com; cmd->error = false; cmd->pending = 0; cmd->hl = NULL; cmd->arglist = NULL; if (arg1) { /* Note: this can send CP_ERR_HOSTLIST to client */ cmd->hl = _hostlist_create_validated(c, arg1); if (cmd->hl == NULL) { _destroy_command(cmd); cmd = NULL; } } else cmd->hl = hostlist_copy(conf_getnodes()); if (cmd && !dev_check_actions(cmd->com, cmd->hl)) { _destroy_command(cmd); _client_printf(c, CP_ERR_UNIMPL); cmd = NULL; } /* NOTE 1: cmd->arglist has a reference count and can persist after we * unlink from it in _destroy_command(). If client goes away prematurely, * actions that write to arglist will still have valid pointers. * NOTE 2: we create arglist for all actions, rather than just query * actions, because we want to allow 'setplugstate' in any context. */ if (cmd) { cmd->arglist = arglist_create(cmd->hl); if (cmd->arglist == NULL) { _destroy_command(cmd); _internal_error_response(c); cmd = NULL; } } return cmd; } /* * Destroy a Command. */ static void _destroy_command(Command * cmd) { if (cmd->hl) hostlist_destroy(cmd->hl); if (cmd->arglist) arglist_unlink(cmd->arglist); xfree(cmd); } /* helper for _parse_input that deletes leading & trailing whitespace */ static char *_strip_whitespace(char *str) { char *head = str; char *tail = str + strlen(str) - 1; while (*head && isspace(*head)) head++; while (tail > head && isspace(*tail)) *tail-- = '\0'; return head; } /* * Parse a line of input and create a Command (and enqueue device actions) * if needed. */ static void _parse_input(Client * c, char *input) { char *str = _strip_whitespace(input); char arg1[CP_LINEMAX]; Command *cmd = NULL; memset(arg1, 0, CP_LINEMAX); /* NOTE: sscanf is safe because 'str' is guaranteed to be < CP_LINEMAX */ if (strlen(str) >= CP_LINEMAX) { _client_printf(c, CP_ERR_TOOLONG); /* error: too long */ } else if (c->cmd != NULL) { _client_printf(c, CP_ERR_CLIBUSY); /* error: busy */ return; /* no prompt */ } else if (!strncasecmp(str, CP_HELP, strlen(CP_HELP))) { _client_printf(c, CP_INFO_HELP); /* help */ _client_printf(c, CP_RSP_QRY_COMPLETE); } else if (!strncasecmp(str, CP_NODES, strlen(CP_NODES))) { _client_query_nodes_reply(c); /* nodes */ } else if (!strncasecmp(str, CP_TELEMETRY, strlen(CP_TELEMETRY))) { c->telemetry = !c->telemetry; /* telemetry */ _client_printf(c, CP_RSP_TELEMETRY, c->telemetry ? "ON" : "OFF"); } else if (!strncasecmp(str, CP_EXPRANGE, strlen(CP_EXPRANGE))) { c->exprange = !c->exprange; /* exprange */ _client_printf(c, CP_RSP_EXPRANGE, c->exprange ? "ON" : "OFF"); } else if (!strncasecmp(str, CP_QUIT, strlen(CP_QUIT))) { c->client_quit = true; _client_printf(c, CP_RSP_QUIT); /* quit */ _handle_write(c); } else if (sscanf(str, CP_ON, arg1) == 1) { /* on hostlist */ cmd = _create_command(c, PM_POWER_ON, arg1); } else if (sscanf(str, CP_OFF, arg1) == 1) { /* off hostlist */ cmd = _create_command(c, PM_POWER_OFF, arg1); } else if (sscanf(str, CP_CYCLE, arg1) == 1) { /* cycle hostlist */ cmd = _create_command(c, PM_POWER_CYCLE, arg1); } else if (sscanf(str, CP_RESET, arg1) == 1) { /* reset hostlist */ cmd = _create_command(c, PM_RESET, arg1); } else if (sscanf(str, CP_BEACON_ON, arg1) == 1) { /* beacon_on hostlist */ cmd = _create_command(c, PM_BEACON_ON, arg1); } else if (sscanf(str, CP_BEACON_OFF, arg1) == 1) { /* beacon_off hostlist*/ cmd = _create_command(c, PM_BEACON_OFF, arg1); } else if (sscanf(str, CP_STATUS, arg1) == 1) { /* status [hostlist] */ cmd = _create_command(c, PM_STATUS_PLUGS, arg1); } else if (!strncasecmp(str, CP_STATUS_ALL, strlen(CP_STATUS_ALL))) { cmd = _create_command(c, PM_STATUS_PLUGS, NULL); } else if (sscanf(str, CP_TEMP, arg1) == 1) { /* temp [hostlist] */ cmd = _create_command(c, PM_STATUS_TEMP, arg1); } else if (!strncasecmp(str, CP_TEMP_ALL, strlen(CP_TEMP_ALL))) { cmd = _create_command(c, PM_STATUS_TEMP, NULL); } else if (sscanf(str, CP_BEACON, arg1) == 1) { /* beacon [hostlist] */ cmd = _create_command(c, PM_STATUS_BEACON, arg1); } else if (!strncasecmp(str, CP_BEACON_ALL, strlen(CP_BEACON_ALL))) { cmd = _create_command(c, PM_STATUS_BEACON, NULL); } else if (sscanf(str, CP_DEVICE, arg1) == 1) { /* device [hostlist] */ _client_query_device_reply(c, arg1); } else if (!strncasecmp(str, CP_DEVICE_ALL, strlen(CP_DEVICE_ALL))) { _client_query_device_reply(c, NULL); } else { /* error: unknown */ _client_printf(c, CP_ERR_UNKNOWN); } /* enqueue device actions and tie up the client if necessary */ if (cmd) { assert(cmd->hl != NULL); dbg(DBG_CLIENT, "_parse_input: enqueuing actions"); cmd->pending = dev_enqueue_actions(cmd->com, cmd->hl, _act_finish, c->telemetry ? _telemetry_printf : NULL, _diag_printf, c->client_id, cmd->arglist); if (cmd->pending == 0) { _client_printf(c, CP_ERR_UNIMPL); _destroy_command(cmd); cmd = NULL; } assert(c->cmd == NULL); c->cmd = cmd; } /* reissue prompt if we didn't queue up any device actions */ if (cmd == NULL && !c->client_quit) _client_printf(c, CP_PROMPT); } /* * Callback for device debugging printfs (sent to client if --telemetry) */ static void _telemetry_printf(int client_id, const char *fmt, ...) { va_list ap; Client *c; char *str; if ((c = _find_client(client_id))) { va_start(ap, fmt); str = hvsprintf(fmt, ap); va_end(ap); _client_printf(c, CP_INFO_TELEMETRY, str); xfree(str); } } /* * Callback for device diagnostics */ static void _diag_printf(int client_id, const char *fmt, ...) { va_list ap; Client *c; char *str; if ((c = _find_client(client_id))) { va_start(ap, fmt); str = hvsprintf(fmt, ap); va_end(ap); _client_printf(c, CP_INFO_DIAG, str); xfree(str); } } /* See chaos/powerman#138. * We don't want these messages syslogged when we run the test suite, * so send them to stderr and when powerman is run as a system service, * systemd redirects stderr to the journal which also usually goes to syslog. */ static void log_state_change(Client *c) { int level = conf_get_plug_log_level(); const char *action; char *hosts; switch (c->cmd->com) { case PM_POWER_ON: action = "powered on"; break; case PM_POWER_OFF: action = "powered off"; break; case PM_POWER_CYCLE: action = "power cycled"; break; case PM_RESET: action = "reset"; break; default: return; } hosts = _xhostlist_ranged_string(c->cmd->hl); // N.B. systemd journal groks prefix fprintf(stderr, "<%d>%s %s%s\n", level, action, hosts, (c->cmd->error == true ? " with errors" : "")); xfree(hosts); } /* * Callback for device action completion. */ static void _act_finish(int client_id, ActError acterr, const char *fmt, ...) { va_list ap; Client *c; char *str; /* if client has gone away do nothing */ if (!(c = _find_client(client_id))) return; assert(c->cmd != NULL); /* handle errors immediately */ if (acterr != ACT_ESUCCESS) { va_start(ap, fmt); str = hvsprintf(fmt, ap); va_end(ap); _client_printf(c, CP_INFO_ACTERROR, str); xfree(str); c->cmd->error = true; /* when done say "completed with errors" */ } /* all actions have called back - return response to client */ if (--c->cmd->pending == 0) { log_state_change(c); switch (c->cmd->com) { case PM_STATUS_PLUGS: /* status */ case PM_STATUS_BEACON: /* beacon */ _client_query_status_reply(c, c->cmd->error); break; case PM_STATUS_TEMP: /* temp */ _client_query_status_reply_nointerp(c, c->cmd->error); break; case PM_POWER_ON: /* on */ case PM_POWER_OFF: /* off */ case PM_BEACON_ON: /* flash */ case PM_BEACON_OFF: /* unflash */ case PM_POWER_CYCLE: /* cycle */ case PM_RESET: /* reset */ _client_power_status_reply(c, c->cmd->error); break; default: assert(false); _internal_error_response(c); break; } /* clean up and re-prompt */ _destroy_command(c->cmd); c->cmd = NULL; _client_printf(c, CP_PROMPT); } } /* * Destroy a client. */ static void _destroy_client(Client *c) { if (c->fd != NO_FD) { dbg(DBG_CLIENT, "_destroy_client: closing fd %d", c->fd); if (close(c->fd) < 0) err(true, "close fd %d", c->fd); c->fd = NO_FD; } if (c->ofd != NO_FD) { dbg(DBG_CLIENT, "_destroy_client: closing fd %d", c->ofd); if (close(c->ofd) < 0) err(true, "close fd %d", c->ofd); c->ofd = NO_FD; } if (c->to) cbuf_destroy(c->to); if (c->from) cbuf_destroy(c->from); if (c->cmd) _destroy_command(c->cmd); if (c->ip) xfree(c->ip); if (c->host) xfree(c->host); xfree(c); if (one_client) server_done = true; } /* helper for _find_client */ static int _match_client(Client *c, void *key) { return (c->client_id == *(int *) key); } /* * Test if a client still exists (by sequence). */ static Client *_find_client(int seq) { return list_find_first(cli_clients, (ListFindF) _match_client, &seq); } /* * Begin listening for clients on configured listen addresses. * This function leaves listen_fds[] (of size listen_fds_len) initialized * with each element either NO_FD or an open fd we are listening on. */ static void _listen_client(void) { int fd, error, i, opt, count; struct addrinfo hints, *res, *r; char *addr, *host, *port; char *what = "nothing"; int saved_errno = 0; List addrs; ListIterator itr; i = 0; count = 0; saved_errno = 0; addrs = conf_get_listen(); itr = list_iterator_create(addrs); while ((addr = list_next(itr))) { host = addr; if (!(port = strchr(addr, ':'))) err_exit(false, "error parsing listen address: %s", addr); *port++ = '\0'; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; /* N.B.: host=NULL, ai_hints=AI_PASSIVE says "any interface", * while host="0.0.0.0" is IPv4-specific INADDR_ANY. */ if ((error = getaddrinfo(host, port, &hints, &res))) err_exit(false, "getaddrinfo: %s", gai_strerror(error)); if (res == NULL) err_exit(false, "listen address has no addrinfo: %s", addr); /* allocate the listen_fds array */ for (r = res; r != NULL; r = r->ai_next) listen_fds_len++; if (listen_fds == NULL) listen_fds = (int *)xmalloc(sizeof(int) * listen_fds_len); else listen_fds = (int *)xrealloc((char *)listen_fds, sizeof(int) * listen_fds_len); /* bind sockets to addresses */ for (r = res; r != NULL; r = r->ai_next, i++) { assert(i < listen_fds_len); listen_fds[i] = NO_FD; if ((fd = socket(r->ai_family, r->ai_socktype, 0)) < 0) { saved_errno = errno; what = "socket"; continue; } opt = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { saved_errno = errno; what = "setsockopt"; close(fd); continue; } nonblock_set(fd); if (bind(fd, r->ai_addr, r->ai_addrlen) < 0) { saved_errno = errno; what = "bind"; close(fd); continue; } if (listen(fd, LISTEN_BACKLOG) < 0) { saved_errno = errno; what = "listen"; close(fd); continue; } listen_fds[i] = fd; count++; } freeaddrinfo(res); } list_iterator_destroy(itr); /* FIXME: dodgy error handling here: As we go through the loop(s) we may * encounter errors that are interesting, however we only display the * most recent one, and then only if no bindable addresses were found. */ if (count == 0) { errno = saved_errno; err_exit(true, "%s", what); } dbg(DBG_CLIENT, "listening on %d sockets", count); } static void _create_client_socket(int fd) { Client *c; struct sockaddr_storage addr; socklen_t addr_size = sizeof(addr); char hbuf[64], pbuf[6]; int error; /* create client data structure */ c = (Client *) xmalloc(sizeof(Client)); c->to = NULL; c->from = NULL; c->cmd = NULL; c->client_id = _next_cli_id(); c->telemetry = false; c->exprange = false; c->ofd = NO_FD; c->client_quit = false; c->fd = accept(fd, (struct sockaddr *)&addr, &addr_size); if (c->fd < 0){ /* client died after it initiated connect and before we could accept * Ref. Stevens, UNP p424 */ if (errno == EWOULDBLOCK || errno == ECONNABORTED || errno == EPROTO || errno == EINTR) { _destroy_client(c); err(true, "_create_client: accept"); return; } err_exit(true, "accept"); } if ((error = getnameinfo((struct sockaddr *)&addr, addr_size, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV))) { _destroy_client(c); err(true, "_create_client: getnameinfo: %s", gai_strerror(error)); return; } c->ip = xstrdup(hbuf); c->port = strtoul(pbuf, NULL, 10); if ((error = getnameinfo((struct sockaddr *)&addr, addr_size, hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD))) err(false, "_create_client: getnameinfo: %s", gai_strerror(error)); else c->host = xstrdup(hbuf); #if HAVE_TCP_WRAPPERS /* get authorization from tcp wrappers */ if (conf_get_use_tcp_wrappers()) { if (!hosts_ctl(DAEMON_NAME, c->host ? c->host : STRING_UNKNOWN, c->ip, STRING_UNKNOWN)) { err(false, "_create_client: tcp wrappers denies %s:%d", c->host ? c->host : c->ip, c->port); _destroy_client(c); return; } } #endif /* create I/O buffers */ c->to = cbuf_create(MIN_CLIENT_BUF, MAX_CLIENT_BUF); c->from = cbuf_create(MIN_CLIENT_BUF, MAX_CLIENT_BUF); nonblock_set(c->fd); /* append to the list of clients */ list_append(cli_clients, c); dbg(DBG_CLIENT, "connect %s:%d fd %d", c->host ? c->host : c->ip, c->port, c->fd); /* prompt the client */ _client_printf(c, CP_VERSION, PACKAGE_VERSION); _client_printf(c, CP_PROMPT); } static void _create_client_stdio(void) { Client *c; /* create client data structure */ c = (Client *) xmalloc(sizeof(Client)); c->cmd = NULL; c->client_id = _next_cli_id(); c->telemetry = false; c->exprange = false; c->client_quit = false; c->fd = STDIN_FILENO; c->ofd = STDOUT_FILENO; c->host = xstrdup("localhost"); c->ip = xstrdup("127.0.0.1"); /* XXX lies */ c->port = 0; c->to = cbuf_create(MIN_CLIENT_BUF, MAX_CLIENT_BUF); c->from = cbuf_create(MIN_CLIENT_BUF, MAX_CLIENT_BUF); nonblock_set(c->fd); nonblock_set(c->ofd); /* append to the list of clients */ list_append(cli_clients, c); /* prompt the client */ _client_printf(c, CP_VERSION, PACKAGE_VERSION); _client_printf(c, CP_PROMPT); } /* * select(2) read handler for the client */ static void _handle_read(Client * c) { int n; int dropped; n = cbuf_write_from_fd(c->from, c->fd, -1, &dropped); if (n < 0) { c->client_quit = true; err(true, "client read error"); return; } if (n == 0) { c->client_quit = true; dbg(DBG_CLIENT, "client read returned EOF"); return; } if (dropped != 0) err(false, "dropped %d bytes of client input", dropped); } /* * select(2) write handler for the client */ static void _handle_write(Client * c) { int n; int ofd = c->ofd != NO_FD ? c->ofd : c->fd; if (c->client_quit) nonblock_clr(ofd); n = cbuf_read_to_fd(c->to, ofd, -1); if (n < 0) { err(true, "write error on client"); c->client_quit = true; } } static void _handle_input(Client *c) { char buf[MAX_CLIENT_BUF]; int len; while ((len = cbuf_read_line(c->from, buf, sizeof(buf), 1)) > 0) _parse_input(c, buf); if (len < 0) err(true, "client cbuf_read_line returned %d", len); } /* * Prep rset/wset/maxfd for the main poll call. */ void cli_pre_poll(xpollfd_t pfd) { ListIterator itr; Client *client; int i; for (i = 0; i < listen_fds_len; i++) { if (listen_fds[i] != NO_FD) { assert(listen_fds[i] >= 0); xpollfd_set(pfd, listen_fds[i], XPOLLIN); } } itr = list_iterator_create(cli_clients); while ((client = list_next(itr))) { if (client->fd < 0) continue; /* set read set bits so select will unblock if the * connection is dropped. */ if (!client->client_quit) xpollfd_set(pfd, client->fd, XPOLLIN); /* need to be in the write set if we are sending anything */ if (!cbuf_is_empty(client->to)) { if (client->ofd != NO_FD) xpollfd_set(pfd, client->ofd, XPOLLOUT); else xpollfd_set(pfd, client->fd, XPOLLOUT); } } list_iterator_destroy(itr); } /* * Handle any client activity (new connection or read/write). */ void cli_post_poll(xpollfd_t pfd) { ListIterator itr; Client *c; int i; for (i = 0; i < listen_fds_len; i++) { if (listen_fds[i] != NO_FD) if ((xpollfd_revents(pfd, listen_fds[i]) & XPOLLIN)) _create_client_socket(listen_fds[i]); } itr = list_iterator_create(cli_clients); while ((c = list_next(itr))) { if (c->fd != NO_FD) { short flags = xpollfd_revents(pfd, c->fd); if (flags & XPOLLERR) err(false, "client poll: error"); if (flags & XPOLLNVAL) err(false, "client poll: fd not open"); if (flags & (XPOLLERR | XPOLLNVAL)) goto client_dead; if (flags & (XPOLLIN | XPOLLHUP)) _handle_read(c); if ((flags & XPOLLOUT)) _handle_write(c); } if (c->ofd != NO_FD) { short flags = xpollfd_revents(pfd, c->ofd); if (flags & XPOLLERR) err(false, "client poll: error"); if (flags & XPOLLHUP) err(false, "client poll: hangup"); if (flags & XPOLLNVAL) err(false, "client poll: fd not open"); if (flags & (XPOLLERR | XPOLLHUP | XPOLLNVAL)) goto client_dead; if (c->fd == NO_FD) goto client_dead; if ((flags & XPOLLOUT)) _handle_write(c); } _handle_input(c); if (c->client_quit && c->cmd == NULL) goto client_dead; continue; client_dead: list_delete(itr); } list_iterator_destroy(itr); } /* hook so daemonization function can avoid closing our fd */ void cli_listen_fds(int **fdsp, int *lenp) { *fdsp = listen_fds; *lenp = listen_fds_len; } bool cli_server_done(void) { return server_done; } void cli_start(bool use_stdio) { if (use_stdio) { _create_client_stdio(); one_client = true; } else _listen_client(); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/client.h000066400000000000000000000013301467035776500174400ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_CLIENT_H #define PM_CLIENT_H void cli_init(void); void cli_fini(void); void cli_start(bool use_stdio); void cli_listen_fds(int **fds, int *len); bool cli_server_done(void); void cli_post_poll(xpollfd_t pfd); void cli_pre_poll(xpollfd_t pfd); #endif /* PM_CLIENT_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/client_proto.h000066400000000000000000000122371467035776500206730ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2002 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_CLIENT_PROTO_H #define PM_CLIENT_PROTO_H /* * Line oriented request/response protocol for powerman daemon. * 1. client connects * 2. server sends version string * 3. server sends prompt * 4. client sends command * 5. server sends response (see note under Responses below) * If not quit, goto 3 */ #define CP_LINEMAX 131072 /* max request/response line length */ #define CP_EOL "\r\n" /* line terminator */ #define CP_PROMPT "powerman> " /* prompt */ #define CP_VERSION "001 %s" CP_EOL /* * Requests */ #define CP_HELP "help" #define CP_QUIT "quit" #define CP_RESET "reset %s" #define CP_CYCLE "cycle %s" #define CP_ON "on %s" #define CP_OFF "off %s" #define CP_NODES "nodes" #define CP_DEVICE "device %s" #define CP_DEVICE_ALL "device" #define CP_STATUS "status %s" #define CP_STATUS_ALL "status" #define CP_TEMP "temp %s" #define CP_TEMP_ALL "temp" #define CP_BEACON "beacon %s" #define CP_BEACON_ALL "beacon" #define CP_BEACON_ON "flash %s" #define CP_BEACON_OFF "unflash %s" #define CP_TELEMETRY "telemetry" #define CP_EXPRANGE "exprange" /* * Responses - * 1XX's are successes (indicates end of response) * 2XX's are failures (indicates end of response) * 3XX's are informational messages (more data coming) * Responses can be multi-line. Client knows response is complete when * it reads a 1XX or 2XX line. */ #define CP_IS_SUCCESS(i) ((i) >= 100 && (i) < 200) #define CP_IS_FAILURE(i) ((i) >= 200 && (i) < 300) #define CP_IS_ALLDONE(i) ((i) >= 100 && (i) < 300) /* success 1xx */ #define CP_RSP_QUIT "101 Goodbye" CP_EOL #define CP_RSP_COM_COMPLETE "102 Command completed successfully" CP_EOL #define CP_RSP_QRY_COMPLETE "103 Query complete" CP_EOL #define CP_RSP_TELEMETRY "104 Telemetry %s" CP_EOL #define CP_RSP_EXPRANGE "105 Hostrange expansion %s" CP_EOL /* failure 2xx */ #define CP_ERR_UNKNOWN "201 Unknown command" CP_EOL #define CP_ERR_PARSE "202 Parse error" CP_EOL #define CP_ERR_TOOLONG "203 Command too long" CP_EOL #define CP_ERR_INTERNAL "204 Internal powermand error: %s::%d" CP_EOL #define CP_ERR_HOSTLIST "205 Hostlist error: %s" CP_EOL #define CP_ERR_CLIBUSY "208 Command in progress" CP_EOL #define CP_ERR_NOSUCHNODES "209 No such nodes: %s" CP_EOL #define CP_ERR_COM_COMPLETE "210 Command completed with errors" CP_EOL #define CP_ERR_QRY_COMPLETE "211 Query completed with errors" CP_EOL #define CP_ERR_UNIMPL "213 Command cannot be handled by power control device(s)" CP_EOL /* informational 3xx */ #define CP_INFO_HELP \ "301 nodes - query node list" CP_EOL \ "301 device [] - query power control device status" CP_EOL \ "301 status [] - query power status" CP_EOL \ "301 on - power on" CP_EOL \ "301 off - power off" CP_EOL \ "301 cycle - power cycle" CP_EOL \ "301 reset - hardware reset (if available)" CP_EOL \ "301 temp [] - query temperature (if available)" CP_EOL \ "301 beacon [] - query beacon status (if available)" CP_EOL \ "301 flash - set beacon to ON (if available)" CP_EOL \ "301 unflash - set beacon to OFF (if available)" CP_EOL \ "301 telemetry - toggle telemetry display" CP_EOL \ "301 exprange - toggle host range expansion" CP_EOL \ "301 help - display help" CP_EOL \ "301 quit - logout" CP_EOL #define CP_INFO_STATUS \ "302 on: %s" CP_EOL \ "302 off: %s" CP_EOL \ "302 unknown: %s" CP_EOL #define CP_INFO_XSTATUS "303 %s: %s" CP_EOL #define CP_INFO_DEVICE \ "304 %s: state=%s reconnects=%-3.3d actions=%-3.3d type=%s hosts=%s" CP_EOL #define CP_INFO_TELEMETRY "305 %s" CP_EOL #define CP_INFO_NODES "306 %s" CP_EOL #define CP_INFO_XNODES "307 %s" CP_EOL #define CP_INFO_ACTERROR "308 %s" CP_EOL #define CP_INFO_DIAG "309 %s" CP_EOL #endif /* PM_CLIENT_PROTO_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/debug.c000066400000000000000000000054131467035776500172510ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include "xmalloc.h" #include "debug.h" #define DBG_BUFLEN 1024 static unsigned long dbg_channel_mask = 0; void dbg_setmask(unsigned long mask) { dbg_channel_mask = mask; } static char *_channel_name(unsigned long channel) { static struct { unsigned long chan; char *desc; } tab[] = DBG_NAME_TAB; int i = 0; while (tab[i].chan != 0) { if (tab[i].chan == channel) break; i++; } return (tab[i].chan == 0 ? "" : tab[i].desc); } static char *_time(void) { time_t now = time(NULL); char *str = ctime(&now); str[strlen(str) - 1] = '\0'; /* lose trailing \n */ return str; } /* * Report message on stdout/syslog if dbg_channel_mask permits. */ void dbg_wrapped(unsigned long channel, const char *fmt, ...) { va_list ap; if ((channel & dbg_channel_mask) == channel) { char buf[DBG_BUFLEN]; va_start(ap, fmt); vsnprintf(buf, DBG_BUFLEN, fmt, ap); /* overflow ignored on purpose */ va_end(ap); fprintf(stderr, "%s %s: %s\n", _time(), _channel_name(channel), buf); } } /* * Convert memory to string, turning non-printable character into "C" * representation. * mem (IN) target memory * len (IN) number of characters to convert * RETURN string (caller must free) */ char *dbg_memstr(char *mem, int len) { int i, j; int strsize = len * 4; /* worst case */ char *str = xmalloc(strsize + 1); for (i = j = 0; i < len; i++) { switch (mem[i]) { case '\r': strcpy(&str[j], "\\r"); j += 2; break; case '\n': strcpy(&str[j], "\\n"); j += 2; break; case '\t': strcpy(&str[j], "\\t"); j += 2; break; default: if (isprint(mem[i])) str[j++] = mem[i]; else { sprintf(&str[j], "\\%.3o", mem[i]); j += 4; } break; } assert(j <= strsize || i == len); } str[j] = '\0'; return str; } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/debug.h000066400000000000000000000025561467035776500172630ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_DEBUG_H #define PM_DEBUG_H #include #define DBG_ALWAYS 0x0000 #define DBG_DEVICE 0x0001 #define DBG_POLL 0x0002 #define DBG_CLIENT 0x0004 #define DBG_ACTION 0x0008 #define DBG_MEMORY 0x0010 #define DBG_TELNET 0x0020 #define DBG_NAME_TAB { \ { DBG_DEVICE, "device" }, \ { DBG_POLL, "poll" }, \ { DBG_CLIENT, "client" }, \ { DBG_ACTION, "action" }, \ { DBG_MEMORY, "memory" }, \ { DBG_TELNET, "telnet" }, \ { 0, NULL } \ } void dbg_setmask(unsigned long mask); void dbg_wrapped(unsigned long channel, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); char *dbg_memstr(char *mem, int len); #define dbg(channel, fmt...) dbg_wrapped(channel, fmt) #endif /* PM_DEBUG_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/device.c000066400000000000000000001404341467035776500174250ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* Primary entry points to this module are: * * initialization - dev_init() and dev_fini() are called from powermand. * dev_initial_connect(), called one time only after dev_init(), begins * connection establishment to all devices. * * parser - at config file parse time, each device is instantiated by * the dev_create() function, which puts the device on the local 'dev_devices' * list. * * client - calls dev_enqueue_actions() to cause one type of script to * run across possibly multiple devices. This function returns an "action * count", and each time an action completes, a callback is made to the client * which decrements its count. When the count reaches zero, the client knows * this module is all done operating on its behalf and can respond to the * user. * * select - the select/poll loop calls the dev_pre_poll() and dev_post_poll() * functions, the former to make a list of file descriptors which when ready * should unblock select/poll; the latter to move data between device cbufs * and the device file descriptors, to manage timeouts, and to move * device scripts along when new state develops (e.g. data in cbufs). * * FIXME: the Device type is not externally opaque as it ought to be: * - parser creates Device with dev_create() but then initializes lots * of Device fields based on parsed device specification * - client pulls out plug names & stats for --device response */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include "list.h" #include "hostlist.h" #include "cbuf.h" #include "parse_util.h" #include "xpoll.h" #include "xmalloc.h" #include "xregex.h" #include "pluglist.h" #include "device.h" #include "arglist.h" #include "device_private.h" #include "error.h" #include "debug.h" #include "client_proto.h" #include "hprintf.h" #include "xtime.h" /* ExecCtx's are the state for the execution of a block of statements. * They are stacked on the Action (new ExecCtx pushed when executing an * inner block). */ typedef struct { List plugs; /* name(s) used for send "%s" (NULL=all) */ List block; /* List of stmts */ ListIterator stmtitr; /* next stmt in block */ Stmt *cur; /* current stmt */ PlugListIterator plugitr; /* used by foreach */ PlugList pluglist; /* pluglist if foreach is ranged */ bool processing; /* flag used by stmts, ifon/ifoff */ } ExecCtx; /* Actions are queued on a device and executed one at a time. Each action * represents a request to run a particular script on a device, for a set of * plugs. Actions can be enqueued by the client or internally (e.g. login). */ #define MAX_LEVELS 2 typedef struct { int com; /* one of the PM_* script types */ List exec; /* stack of ExecCtxs (outer block is first) */ ActionCB complete_fun; /* callback for action completion */ VerbosePrintf vpf_fun; /* callback for device telemetry */ DiagPrintf dpf_fun; /* callback for device diagnostics */ int client_id; /* client id so completion can find client */ ActError errnum; /* errno for action */ struct timeval time_stamp; /* time stamp for timeouts */ struct timeval delay_start; /* time stamp for delay completion */ ArgList arglist; /* argument for query actions (list of Arg's) */ } Action; static bool _process_stmt(Device *dev, Action *act, ExecCtx *e, struct timeval *timeout); static bool _process_ifonoff(Device *dev, Action *act, ExecCtx *e); static bool _process_foreach(Device *dev, Action *act, ExecCtx *e); static bool _process_setplugstate(Device * dev, Action *act, ExecCtx *e); static bool _process_setresult(Device * dev, Action *act, ExecCtx *e); static bool _process_expect(Device * dev, Action *act, ExecCtx *e); static bool _process_send(Device * dev, Action *act, ExecCtx *e); static bool _process_delay(Device * dev, Action *act, ExecCtx *e, struct timeval *timeout); static int _match_name(Device * dev, void *key); static bool _handle_read(Device * dev); static bool _handle_write(Device * dev); static void _process_action(Device * dev, struct timeval *timeout); static bool _timeout(struct timeval *timestamp, struct timeval *timeout, struct timeval *timeleft); static int _get_all_script(Device * dev, int com); static int _get_ranged_script(Device * dev, int com); static int _enqueue_actions(Device * dev, int com, hostlist_t hl, ActionCB complete_fun, VerbosePrintf vpf_fun, DiagPrintf dpf_fun, int client_id, ArgList arglist); static Action *_create_action(Device * dev, int com, List plugs, ActionCB complete_fun, VerbosePrintf vpf_fun, DiagPrintf dpf_fun, int client_id, ArgList arglist); static int _enqueue_targeted_actions(Device * dev, int com, hostlist_t hl, ActionCB complete_fun, VerbosePrintf vpf_fun, DiagPrintf dpf_fun, int client_id, ArgList arglist); static char *_getregex_buf(cbuf_t b, xregex_t re, xregex_match_t xm); static bool _command_needs_device(Device * dev, hostlist_t hl); static void _enqueue_ping(Device * dev, struct timeval *timeout); static void _enqueue_login(Device *dev); static void _disconnect(Device * dev); static bool _connect(Device * dev); static bool _reconnect(Device * dev, struct timeval *timeout); static bool _time_to_reconnect(Device * dev, struct timeval *timeout); static List dev_devices = NULL; static bool short_circuit_delay = false; static void _dbg_actions(Device * dev) { char tmpstr[1024]; Action *act; ListIterator itr; tmpstr[0] = '\0'; itr = list_iterator_create(dev->acts); while ((act = list_next(itr))) { snprintf(tmpstr + strlen(tmpstr), sizeof(tmpstr) - strlen(tmpstr), "%d,", act->com); } list_iterator_destroy(itr); if (strlen(tmpstr) > 0) tmpstr[strlen(tmpstr) - 1] = '\0'; /* zap trailing comma */ dbg(DBG_ACTION, "%s: %s", dev->name, tmpstr); } static void _memtrans(char *m, int len, char from, char to) { int i; for (i = 0; i < len; i++) { if (m[i] == from) m[i] = to; } } /* * Apply regular expression to the contents of a cbuf_t. * If there is a match, return (and consume) from the beginning * of the buffer to the last character of the match. * NOTE: embedded \0 chars are converted to \377 because libc regex * functions would treat these as string terminators. As a result, * \0 chars cannot be matched explicitly. * b (IN) buffer to apply regex to * re (IN) regular expression * xm (OUT) subexpression matches * RETURN String match (caller must free) or NULL if no match */ static char *_getregex_buf(cbuf_t b, xregex_t re, xregex_match_t xm) { int bytes_peeked, dropped, matchlen; char *str; int maxpeeksize = cbuf_used(b); str = xmalloc(maxpeeksize + 1); bytes_peeked = cbuf_peek(b, str, maxpeeksize); if (bytes_peeked <= 0) { /* FIXME: any -1 handling needed? */ if (bytes_peeked < 0) err(true, "_getregex_buf: cbuf_peek returned %d", bytes_peeked); xfree(str); return NULL; } assert(bytes_peeked <= maxpeeksize); _memtrans(str, bytes_peeked, '\0', '\377'); str[bytes_peeked] = '\0'; if (!xregex_exec(re, str, xm)) { xfree(str); return NULL; } matchlen = xregex_match_strlen(xm); dropped = cbuf_drop(b, matchlen); if (dropped != matchlen) err((dropped < 0), "_getregex_buf: cbuf_drop returned %d", dropped); return str; } static ExecCtx *_create_exec_ctx(Device *dev, List block, List plugs) { ExecCtx *new = (ExecCtx *)xmalloc(sizeof(ExecCtx)); new->stmtitr = list_iterator_create(block); new->cur = list_next(new->stmtitr); new->block = block; new->plugs = plugs; new->plugitr = NULL; new->processing = false; return new; } static void _destroy_exec_ctx(ExecCtx *e) { if (e->stmtitr != NULL) list_iterator_destroy(e->stmtitr); e->stmtitr = NULL; e->cur = NULL; if (e->plugs) list_destroy(e->plugs); if (e->pluglist) pluglist_destroy(e->pluglist); e->plugs = NULL; xfree(e); } static void _rewind_action(Action *act) { ExecCtx *e; /* get back to the context for the outer block */ while ((e = list_pop(act->exec))) { if (list_is_empty(act->exec)) { list_push(act->exec, e); break; } _destroy_exec_ctx(e); } /* reset outer block iterator and current pointer */ if (e) { list_iterator_reset(e->stmtitr); e->cur = list_next(e->stmtitr); } } static Action *_create_action(Device * dev, int com, List plugs, ActionCB complete_fun, VerbosePrintf vpf_fun, DiagPrintf dpf_fun, int client_id, ArgList arglist) { Action *act; ExecCtx *e; dbg(DBG_ACTION, "_create_action: %d", com); act = (Action *) xmalloc(sizeof(Action)); act->com = com; act->complete_fun = complete_fun; act->vpf_fun = vpf_fun; act->dpf_fun = dpf_fun; act->client_id = client_id; act->exec = list_create((ListDelF)_destroy_exec_ctx); e = _create_exec_ctx(dev, dev->scripts[act->com], plugs); list_push(act->exec, e); act->errnum = ACT_ESUCCESS; act->arglist = arglist ? arglist_link(arglist) : NULL; timerclear(&act->time_stamp); return act; } static void _destroy_action(Action * act) { dbg(DBG_ACTION, "_destroy_action: %d", act->com); if (act->exec) list_destroy(act->exec); act->exec = NULL; if (act->arglist) arglist_unlink(act->arglist); act->arglist = NULL; xfree(act); } /* initialize this module */ void dev_init(bool Sopt) { dev_devices = list_create((ListDelF) dev_destroy); short_circuit_delay = Sopt; } /* tear down this module */ void dev_fini(void) { list_destroy(dev_devices); } /* add a device to the device list (called from config file parser) */ void dev_add(Device * dev) { list_append(dev_devices, dev); } /* * Client needs access to device list to process "devices" query. */ List dev_getdevices(void) { return dev_devices; } /* * Test whether timeout has occurred * time_stamp (IN) * timeout (IN) * timeleft (OUT) if timeout has not occurred, put time left here * RETURN true if (time_stamp + timeout > now) */ static bool _timeout(struct timeval *time_stamp, struct timeval *timeout, struct timeval *timeleft) { struct timeval now; struct timeval limit; bool result = false; /* limit = time_stamp + timeout */ timeradd(time_stamp, timeout, &limit); if (gettimeofday(&now, NULL) < 0) err_exit(true, "gettimeofday"); if (timercmp(&now, &limit, >=)) /* if now >= limit */ result = true; if (result == false) timersub(&limit, &now, timeleft); /* timeleft = limit - now */ else timerclear(timeleft); return result; } /* * If tv is less than timeout, or timeout is zero, set timeout = tv. */ void _update_timeout(struct timeval *timeout, struct timeval *tv) { if (timercmp(tv, timeout, <) || !timerisset(timeout)) *timeout = *tv; } /* * Helper for _reconnect(). * Return true if OK to attempt reconnect. If false, put the time left * in timeout if it is less than timeout or if timeout is zero. */ static bool _time_to_reconnect(Device * dev, struct timeval *timeout) { static int rtab[] = { 1, 2, 4, 8, 15, 30, 60 }; int max_rtab_index = sizeof(rtab) / sizeof(int) - 1; int rix = dev->retry_count - 1; struct timeval timeleft, retry; bool reconnect = true; if (dev->retry_count > 0) { timerclear(&retry); retry.tv_sec = rtab[rix > max_rtab_index ? max_rtab_index : rix]; if (!_timeout(&dev->last_retry, &retry, &timeleft)) reconnect = false; if (timeout && !reconnect) _update_timeout(timeout, &timeleft); } return reconnect; } static bool _connect(Device * dev) { bool connected; assert(dev->connect != NULL); if (gettimeofday(&dev->last_retry, NULL) < 0) err_exit(true, "gettimeofday"); dev->retry_count++; connected = dev->connect(dev); if (connected) _enqueue_login(dev); return connected; } static bool _reconnect(Device *dev, struct timeval *timeout) { bool connected = false; if (dev->connect_state != DEV_NOT_CONNECTED) _disconnect(dev); if (_time_to_reconnect(dev, timeout)) connected = _connect(dev); return connected; } /* helper for dev_check_actions/dev_enqueue_actions */ static bool _command_needs_device(Device * dev, hostlist_t hl) { bool needed = false; PlugListIterator itr; Plug *plug; itr = pluglist_iterator_create(dev->plugs); while ((plug = pluglist_next(itr))) { if (plug->node != NULL && hostlist_find(hl, plug->node) != -1) { needed = true; break; } } pluglist_iterator_destroy(itr); return needed; } /* * Return true if all devices targeted by hostlist implement the * specified action. */ bool dev_check_actions(int com, hostlist_t hl) { Device *dev; ListIterator itr; bool valid = true; assert(hl != NULL); itr = list_iterator_create(dev_devices); while ((dev = list_next(itr))) { if (_command_needs_device(dev, hl)) { if (!dev->scripts[com] && _get_all_script(dev, com) == -1 && _get_ranged_script(dev, com) == -1) { valid = false; break; } } } list_iterator_destroy(itr); return valid; } /* * Translate a command from a client into actions for devices. * Return an action count so the client be notified when all the * actions "check in". */ int dev_enqueue_actions(int com, hostlist_t hl, ActionCB complete_fun, VerbosePrintf vpf_fun, DiagPrintf dpf_fun, int client_id, ArgList arglist) { Device *dev; ListIterator itr; int total = 0; itr = list_iterator_create(dev_devices); while ((dev = list_next(itr))) { int count; if (!dev->scripts[com] && _get_all_script(dev, com) == -1 && _get_ranged_script(dev, com) == -1) continue; /* unimplemented script */ if (hl && !_command_needs_device(dev, hl)) continue; /* uninvolved device */ count = _enqueue_actions(dev, com, hl, complete_fun, vpf_fun, dpf_fun, client_id, arglist); if (count > 0 && dev->connect_state != DEV_CONNECTED) dev->retry_count = 0; /* expedite retries on this device since */ total += count; /* the user is beating on us... */ } list_iterator_destroy(itr); return total; } static int _enqueue_actions(Device * dev, int com, hostlist_t hl, ActionCB complete_fun, VerbosePrintf vpf_fun, DiagPrintf dpf_fun, int client_id, ArgList arglist) { Action *act; int count = 0; switch (com) { case PM_LOG_IN: /* reset script of preempted action so it starts over */ if (!list_is_empty(dev->acts)) { act = list_peek(dev->acts); _rewind_action(act); dbg(DBG_ACTION, "resetting iterator for non-login action"); } act = _create_action(dev, com, NULL, complete_fun, vpf_fun, dpf_fun, client_id, arglist); list_prepend(dev->acts, act); count++; break; case PM_LOG_OUT: case PM_PING: act = _create_action(dev, com, NULL, complete_fun, vpf_fun, dpf_fun, client_id, arglist); list_append(dev->acts, act); count++; break; case PM_POWER_ON: case PM_POWER_OFF: case PM_BEACON_ON: case PM_BEACON_OFF: case PM_POWER_CYCLE: case PM_RESET: case PM_STATUS_PLUGS: case PM_STATUS_TEMP: case PM_STATUS_BEACON: count += _enqueue_targeted_actions(dev, com, hl, complete_fun, vpf_fun, dpf_fun, client_id, arglist); break; default: assert(false); } return count; } /* return "all" version of script if defined else -1 */ static int _get_all_script(Device * dev, int com) { int new = -1; switch (com) { case PM_POWER_ON: if (dev->scripts[PM_POWER_ON_ALL]) new = PM_POWER_ON_ALL; break; case PM_POWER_OFF: if (dev->scripts[PM_POWER_OFF_ALL]) new = PM_POWER_OFF_ALL; break; case PM_POWER_CYCLE: if (dev->scripts[PM_POWER_CYCLE_ALL]) new = PM_POWER_CYCLE_ALL; break; case PM_RESET: if (dev->scripts[PM_RESET_ALL]) new = PM_RESET_ALL; break; case PM_STATUS_PLUGS: if (dev->scripts[PM_STATUS_PLUGS_ALL]) new = PM_STATUS_PLUGS_ALL; break; case PM_STATUS_TEMP: if (dev->scripts[PM_STATUS_TEMP_ALL]) new = PM_STATUS_TEMP_ALL; break; case PM_STATUS_BEACON: if (dev->scripts[PM_STATUS_BEACON_ALL]) new = PM_STATUS_BEACON_ALL; break; default: break; } return new; } /* return "ranged" version of script if defined else -1 */ static int _get_ranged_script(Device * dev, int com) { int new = -1; switch (com) { case PM_POWER_ON: if (dev->scripts[PM_POWER_ON_RANGED]) new = PM_POWER_ON_RANGED; break; case PM_POWER_OFF: if (dev->scripts[PM_POWER_OFF_RANGED]) new = PM_POWER_OFF_RANGED; break; case PM_POWER_CYCLE: if (dev->scripts[PM_POWER_CYCLE_RANGED]) new = PM_POWER_CYCLE_RANGED; break; case PM_RESET: if (dev->scripts[PM_RESET_RANGED]) new = PM_RESET_RANGED; break; case PM_BEACON_ON: if (dev->scripts[PM_BEACON_ON_RANGED]) new = PM_BEACON_ON_RANGED; break; case PM_BEACON_OFF: if (dev->scripts[PM_BEACON_OFF_RANGED]) new = PM_BEACON_OFF_RANGED; break; default: break; } return new; } static bool _is_query_action(int com) { switch (com) { case PM_STATUS_PLUGS: case PM_STATUS_PLUGS_ALL: case PM_STATUS_TEMP: case PM_STATUS_TEMP_ALL: case PM_STATUS_BEACON: case PM_STATUS_BEACON_ALL: return true; default: return false; } /*NOTREACHED*/ } static int _enqueue_targeted_actions(Device * dev, int com, hostlist_t hl, ActionCB complete_fun, VerbosePrintf vpf_fun, DiagPrintf dpf_fun, int client_id, ArgList arglist) { List new_acts = list_create((ListDelF) _destroy_action); bool all = true; Plug *plug; PlugListIterator itr; int count = 0; Action *act; List ranged_plugs = NULL; int used_ranged_plugs = 0; assert(hl != NULL); if (!(ranged_plugs = list_create((ListDelF)NULL))) goto cleanup; itr = pluglist_iterator_create(dev->plugs); while ((plug = pluglist_next(itr))) { /* antisocial to gratuitously turn on/off unused plug */ if (plug->node == NULL) { all = false; continue; } /* check if node name for plug matches the target */ if (hostlist_find(hl, plug->node) == -1) { all = false; continue; } if (!list_append(ranged_plugs, plug)) goto cleanup; /* append action to 'new_acts' */ if (dev->scripts[com] != NULL) { /* maybe we only have _ALL... */ List plugs; if (!(plugs = list_create((ListDelF)NULL))) goto cleanup; if (!list_append(plugs, plug)) { list_destroy(plugs); goto cleanup; } act = _create_action(dev, com, plugs, complete_fun, vpf_fun, dpf_fun, client_id, arglist); list_append(new_acts, act); } } pluglist_iterator_destroy(itr); /* special case, if singlet script available and we're only * targeting one plug, use singlet script over other possible * choices below. */ if (dev->scripts[com] != NULL && list_count(new_acts) == 1) { while ((act = list_pop(new_acts))) { list_append(dev->acts, act); count++; } } /* Try _all version of script. * * - use if action is a query, unless no singlet version exists * (i.e. if there is no singlet version, we have to use the _all * version) */ if (count == 0) { if (all || (_is_query_action(com) && dev->scripts[com] == NULL)) { int ncom = _get_all_script(dev, com); if (ncom != -1) { act = _create_action(dev, ncom, NULL, complete_fun, vpf_fun, dpf_fun, client_id, arglist); list_append(dev->acts, act); count++; } } } /* _all didn't work, try _ranged. */ if (count == 0) { int ncom = _get_ranged_script(dev, com); if (ncom != -1) { act = _create_action(dev, ncom, ranged_plugs, complete_fun, vpf_fun, dpf_fun, client_id, arglist); list_append(dev->acts, act); used_ranged_plugs++; count++; } } /* _all and _ranged didn't work, we must use singlet version */ if (count == 0) { while ((act = list_pop(new_acts))) { list_append(dev->acts, act); count++; } } cleanup: list_destroy(new_acts); if (!used_ranged_plugs) list_destroy(ranged_plugs); return count; } /* Called upon success of connect or finish_connect device methods. */ static void _enqueue_login(Device *dev) { _enqueue_actions(dev, PM_LOG_IN, NULL, NULL, NULL, NULL, 0, NULL); } static void _disconnect(Device * dev) { Action *act; assert(dev->disconnect != NULL); dev->disconnect(dev); /* empty buffers */ cbuf_flush(dev->from); cbuf_flush(dev->to); /* update state */ dev->connect_state = DEV_NOT_CONNECTED; dev->logged_in = false; /* delete PM_LOG_IN action queued for this device, if any */ if (((act = list_peek(dev->acts)) != NULL) && act->com == PM_LOG_IN) _destroy_action(list_dequeue(dev->acts)); } static void _act_completion(Action *act, Device *dev) { assert(act->complete_fun != NULL); switch (act->errnum) { case ACT_ECONNECTTIMEOUT: act->complete_fun(act->client_id, act->errnum, "%s: connect timeout", dev->name); break; case ACT_ELOGINTIMEOUT: act->complete_fun(act->client_id, act->errnum, "%s: login timeout", dev->name); break; case ACT_EEXPFAIL: act->complete_fun(act->client_id, act->errnum, "%s: action timed out waiting for expected response", dev->name); break; case ACT_EABORT: act->complete_fun(act->client_id, act->errnum, "%s: action aborted due to previous action timeout", dev->name); break; case ACT_ESUCCESS: act->complete_fun(act->client_id, act->errnum, NULL); break; } } /* * Process the script for the current action for this device. * Update timeout and return if one of the script elements stalls. * Start the next action if we complete this one. */ static void _process_action(Device * dev, struct timeval *timeout) { bool stalled = false; Action *act; while ((act = list_peek(dev->acts)) && !stalled) { struct timeval timeleft; ExecCtx *e = list_peek(act->exec); assert(e != NULL); dbg(DBG_ACTION, "_process_action: processing action %d", act->com); _dbg_actions(dev); /* initialize timeout (action is brand new) */ if (!timerisset(&act->time_stamp)) if (gettimeofday(&act->time_stamp, NULL) < 0) err_exit(true, "gettimeofday"); /* timeout exceeded? */ if (_timeout(&act->time_stamp, &dev->timeout, &timeleft)) { if (!(dev->connect_state == DEV_CONNECTED)) act->errnum = ACT_ECONNECTTIMEOUT; else if (!dev->logged_in) { act->errnum = ACT_ELOGINTIMEOUT; } else act->errnum = ACT_EEXPFAIL; if (act->vpf_fun) { static char mem[MAX_DEV_BUF]; int len = cbuf_peek(dev->from, mem, MAX_DEV_BUF); char *memstr = dbg_memstr(mem, len); if (!(dev->connect_state == DEV_CONNECTED)) act->vpf_fun(act->client_id, "connect(%s): timeout", dev->name); else act->vpf_fun(act->client_id, "recv(%s): '%s'", dev->name, memstr); xfree(memstr); } /* not connected but timeout not yet exceeded */ } else if (!(dev->connect_state == DEV_CONNECTED)) { stalled = true; /* not connected */ /* connected - process statements */ } else { /* If a statement has an inner block to execute, it pushes a new * ExecCtx onto the action's exec stack and returns. We notice * the top of the exec stack has changed and try to exec the next * stmt (now of the new context) and so on. When the inner block * is done, the stack is popped and the "current" stmt is back to * the one that initiated the inner block. */ do { e = list_peek(act->exec); stalled = !_process_stmt(dev, act, e, timeout); } while (e != list_peek(act->exec)); } /* stalled - update timeout for select */ if (stalled) { _update_timeout(timeout, &timeleft); /* most recently attempted stmt completed successfully */ } else if (act->errnum == ACT_ESUCCESS) { e->cur = list_next(e->stmtitr); /* next stmt this block */ if (!e->cur) { /* ...or new block */ ExecCtx *e2 = list_pop(act->exec); assert(e2 == e); _destroy_exec_ctx(e2); e = list_peek(act->exec); } /* completed action successfully! */ if (e == NULL) { if (act->com == PM_LOG_IN) dev->logged_in = true; if (act->complete_fun) _act_completion(act, dev); _destroy_action(list_dequeue(dev->acts)); dev->stat_successful_actions++; } /* most recently attempted stmt completed with error */ } else { ActError res = act->errnum; /* save for ref after _destroy_action */ if (act->complete_fun) _act_completion(act, dev); _destroy_action(list_dequeue(dev->acts)); /* if one action failed, abort the rest in the device queue * in preparation for reconnect. */ while ((act = list_dequeue(dev->acts)) != NULL) { act->errnum = (res == ACT_EEXPFAIL ? ACT_EABORT : res); if (act->complete_fun) _act_completion(act, dev); _destroy_action(act); } /* reconnect/login if expect timed out */ if ((dev->connect_state == DEV_CONNECTED)) { dbg(DBG_DEVICE, "_process_action: disconnecting due to error"); _reconnect(dev, timeout); break; } } } /* while loop */ } bool _process_stmt(Device *dev, Action *act, ExecCtx *e, struct timeval *timeout) { bool finished = 0; switch (e->cur->type) { case STMT_EXPECT: finished = _process_expect(dev, act, e); break; case STMT_SEND: finished = _process_send(dev, act, e); break; case STMT_SETPLUGSTATE: finished = _process_setplugstate(dev, act, e); break; case STMT_SETRESULT: finished = _process_setresult(dev, act, e); break; case STMT_DELAY: finished = _process_delay(dev, act, e, timeout); break; case STMT_FOREACHPLUG: case STMT_FOREACHNODE: finished = _process_foreach(dev, act, e); break; case STMT_IFON: case STMT_IFOFF: finished = _process_ifonoff(dev, act, e); break; } return finished; } static bool _process_foreach(Device *dev, Action *act, ExecCtx *e) { bool finished = true; ExecCtx *new; Plug *plug = NULL; /* we store a plug iterator in the ExecCtx */ if (e->plugitr == NULL) { if (act->com == PM_POWER_ON_RANGED || act->com == PM_POWER_OFF_RANGED || act->com == PM_POWER_CYCLE_RANGED || act->com == PM_RESET_RANGED || act->com == PM_BEACON_ON_RANGED || act->com == PM_BEACON_OFF_RANGED) { assert(e->plugs); if (!e->pluglist) { if (!(e->pluglist = pluglist_copy_from_list(e->plugs))) goto cleanup; } e->plugitr = pluglist_iterator_create(e->pluglist); } else e->plugitr = pluglist_iterator_create(dev->plugs); } /* Each time the inner block is executed, its argument will be * a new plug name. Pick that up here. */ if (e->cur->type == STMT_FOREACHPLUG) { plug = pluglist_next(e->plugitr); } else if (e->cur->type == STMT_FOREACHNODE) { do { plug = pluglist_next(e->plugitr); } while (plug && plug->node == NULL); } else { assert(0); } /* plug list not exhausted? start a new execution context for this block */ if (plug != NULL) { List plugs; if (!(plugs = list_create((ListDelF)NULL))) goto cleanup; if (!list_append(plugs, plug)) { list_destroy(plugs); goto cleanup; } new = _create_exec_ctx(dev, e->cur->u.foreach.stmts, plugs); list_push(act->exec, new); } else { pluglist_iterator_destroy(e->plugitr); e->plugitr = NULL; } /* we won't be called again if we don't push a new context */ cleanup: return finished; } static bool _process_ifonoff(Device *dev, Action *act, ExecCtx *e) { bool finished = true; if (e->processing) { /* if returning from subblock, we are done */ e->processing = false; } else { InterpState state = ST_UNKNOWN; bool condition = false; ExecCtx *new; if (e->plugs && list_count(e->plugs) > 0) { Plug *plug = list_peek(e->plugs); Arg *arg = arglist_find(act->arglist, plug->node); if (arg) state = arg->state; } if (e->cur->type == STMT_IFON && state == ST_ON) condition = true; else if (e->cur->type == STMT_IFOFF && state == ST_OFF) condition = true; else if (state == ST_UNKNOWN) { act->errnum = ACT_EEXPFAIL; /* FIXME */ } /* condition met? start a new execution context for this block */ if (condition) { List plugs; ListIterator itr; Plug *plug; e->processing = true; /* achu: previous context's plugs could get destroy, * so must copy plugs to a new list. */ if (!(plugs = list_create((ListDelF)NULL))) goto cleanup; if (!(itr = list_iterator_create(e->plugs))) { list_destroy(plugs); goto cleanup; } while ((plug = list_next(itr))) { if (!list_append(plugs, plug)) { list_destroy(plugs); list_iterator_destroy(itr); goto cleanup; } } new = _create_exec_ctx(dev, e->cur->u.ifonoff.stmts, plugs); list_push(act->exec, new); list_iterator_destroy(itr); } } cleanup: return finished; } static bool _process_setplugstate(Device *dev, Action *act, ExecCtx *e) { bool finished = true; char *plug_name = NULL; /* * Usage: setplugstate [plug] status [interps] * plug can be literal plug name, or regex match, or omitted, * (implying target plug name). */ if (e->cur->u.setplugstate.plug_name) /* literal */ plug_name = xstrdup(e->cur->u.setplugstate.plug_name); if (!plug_name) /* regex match */ plug_name = xregex_match_sub_strdup(dev->xmatch, e->cur->u.setplugstate.plug_mp); if (!plug_name && (e->plugs && list_count(e->plugs) > 0)) { Plug *plug = list_peek(e->plugs); if (plug->name) plug_name = xstrdup(plug->name);/* use action target */ } /* if no plug name, do nothing */ if (plug_name) { char *str = xregex_match_sub_strdup(dev->xmatch, e->cur->u.setplugstate.stat_mp); Plug *plug = pluglist_find(dev->plugs, plug_name); if (str && plug && plug->node) { InterpState state = ST_UNKNOWN; ListIterator itr; StateInterp *i; Arg *arg; itr = list_iterator_create(e->cur->u.setplugstate.interps); while ((i = list_next(itr))) { if (xregex_exec(i->re, str, NULL)) { state = i->state; break; } } list_iterator_destroy(itr); if ((arg = arglist_find(act->arglist, plug->node))) { arg->state = state; xfree(arg->val); arg->val = xstrdup(str); } } xfree(str); /* if no match, do nothing */ xfree(plug_name); } return finished; } static bool _process_setresult(Device *dev, Action *act, ExecCtx *e) { bool finished = true; char *plug_name; /* * Usage: setresult regex regexstatus interps */ plug_name = xregex_match_sub_strdup(dev->xmatch, e->cur->u.setresult.plug_mp); /* if no plug name, do nothing */ if (plug_name) { char *str = xregex_match_sub_strdup(dev->xmatch, e->cur->u.setresult.stat_mp); Plug *plug = pluglist_find(dev->plugs, plug_name); if (str && plug && plug->node) { InterpResult result = RT_UNKNOWN; ListIterator itr; ResultInterp *i; Arg *arg; itr = list_iterator_create(e->cur->u.setresult.interps); while ((i = list_next(itr))) { if (xregex_exec(i->re, str, NULL)) { result = i->result; break; } } list_iterator_destroy(itr); if ((arg = arglist_find(act->arglist, plug->node))) { arg->result = result; xfree(arg->val); arg->val = xstrdup(str); } if (arg && result != RT_SUCCESS) { char strbuf[1024]; snprintf(strbuf, sizeof(strbuf), "%s", arg->val); /* remove trailing carriage return or newline */ strbuf[strcspn(strbuf, "\r\n")] = '\0'; act->dpf_fun(act->client_id, "%s: %s", arg->node, strbuf); } } xfree(str); /* if no match, do nothing */ xfree(plug_name); } return finished; } /* return true if expect is finished */ static bool _process_expect(Device *dev, Action *act, ExecCtx *e) { bool finished = false; char *str; xregex_match_recycle(dev->xmatch); if ((str = _getregex_buf(dev->from, e->cur->u.expect.exp, dev->xmatch))) { if (act->vpf_fun) { char *matchstr = xregex_match_strdup(dev->xmatch); char *memstr = dbg_memstr(matchstr, strlen(matchstr)); act->vpf_fun(act->client_id, "recv(%s): '%s'", dev->name, memstr); xfree(memstr); xfree(matchstr); } xfree(str); finished = true; } return finished; } /* * Wrapped hostlist_ranged_string() with internal buffer allocation, * which caller must xfree(). */ #define CHUNKSIZE 80 static char *_xhostlist_ranged_string(hostlist_t hl) { int size = 0; char *str = NULL; do { str = (size == 0) ? xmalloc(CHUNKSIZE) : xrealloc(str, size+CHUNKSIZE); size += CHUNKSIZE; } while (hostlist_ranged_string(hl, size, str) == -1); return str; } static bool _process_send(Device *dev, Action *act, ExecCtx *e) { bool finished = false; /* first time through? */ if (!e->processing) { int dropped = 0; int written; char *str = NULL; if (e->plugs && list_count(e->plugs) > 0) { if (list_count(e->plugs) > 1) { char *names; ListIterator itr = NULL; hostlist_t hl = NULL; Plug *plug; if (!(hl = hostlist_create(NULL))) { err(true, "_process_send(%s): hostlist_create", dev->name); goto range_cleanup; } if (!(itr = list_iterator_create(e->plugs))) { err(true, "_process_send(%s): list_iterator_create", dev->name); goto range_cleanup; } while ((plug = list_next(itr))) { if (!hostlist_push(hl, plug->name)) { err(true, "_process_send(%s): hostlist_push", dev->name); goto range_cleanup; } } hostlist_sort(hl); names = _xhostlist_ranged_string(hl); str = hsprintf(e->cur->u.send.fmt, names); xfree (names); range_cleanup: if (itr) list_iterator_destroy(itr); if (hl) hostlist_destroy(hl); } else { Plug *plug = list_peek(e->plugs); str = hsprintf(e->cur->u.send.fmt, (plug->name ? plug->name : "[unresolved]")); } } else str = hsprintf(e->cur->u.send.fmt, NULL); if (str) { written = cbuf_write(dev->to, str, strlen(str), &dropped); if (written < 0) err(true, "_process_send(%s): cbuf_write returned %d", dev->name, written); else if (dropped > 0) err(false, "_process_send(%s): buffer overrun, %d dropped", dev->name, dropped); else { char *memstr = dbg_memstr(str, strlen(str)); if (act->vpf_fun) act->vpf_fun(act->client_id, "send(%s): '%s'", dev->name, memstr); xfree(memstr); } assert(written < 0 || (dropped == strlen(str) - written)); } e->processing = true; xfree(str); } if (cbuf_is_empty(dev->to)) { /* finished! */ e->processing = false; finished = true; } return finished; } /* return true if delay is finished */ static bool _process_delay(Device *dev, Action *act, ExecCtx *e, struct timeval *timeout) { bool finished = false; struct timeval delay, timeleft; delay = e->cur->u.delay.tv; /* first time */ if (!e->processing) { if (act->vpf_fun) act->vpf_fun(act->client_id, "delay(%s): %ld.%-6.6ld", dev->name, delay.tv_sec, delay.tv_usec); e->processing = true; if (gettimeofday(&act->delay_start, NULL) < 0) err_exit(true, "gettimeofday"); } /* timeout expired? */ if (short_circuit_delay || _timeout(&act->delay_start, &delay, &timeleft)) { e->processing = false; finished = true; } else _update_timeout(timeout, &timeleft); return finished; } Device *dev_create(const char *name) { Device *dev; int i; dev = (Device *) xmalloc(sizeof(Device)); dev->name = xstrdup(name); dev->connect_state = DEV_NOT_CONNECTED; dev->fd = NO_FD; dev->acts = list_create((ListDelF) _destroy_action); dev->xmatch = xregex_match_create(MAX_MATCH_POS); dev->data = NULL; timerclear(&dev->timeout); timerclear(&dev->last_retry); timerclear(&dev->last_ping); timerclear(&dev->ping_period); dev->to = cbuf_create(MIN_DEV_BUF, MAX_DEV_BUF); dev->from = cbuf_create(MIN_DEV_BUF, MAX_DEV_BUF); for (i = 0; i < NUM_SCRIPTS; i++) dev->scripts[i] = NULL; dev->plugs = NULL; dev->retry_count = 0; dev->stat_successful_connects = 0; dev->stat_successful_actions = 0; return dev; } /* helper for dev_findbyname */ static int _match_name(Device * dev, void *key) { return (strcmp(dev->name, (char *) key) == 0); } Device *dev_findbyname(char *name) { return list_find_first(dev_devices, (ListFindF) _match_name, name); } void dev_destroy(Device * dev) { int i; if (dev->connect_state == DEV_CONNECTED) dev->disconnect(dev); xfree(dev->name); xfree(dev->specname); if (dev->data) { assert(dev->destroy != NULL); dev->destroy(dev->data); } list_destroy(dev->acts); if (dev->plugs) pluglist_destroy(dev->plugs); for (i = 0; i < NUM_SCRIPTS; i++) if (dev->scripts[i] != NULL) list_destroy(dev->scripts[i]); cbuf_destroy(dev->to); cbuf_destroy(dev->from); xregex_match_destroy(dev->xmatch); xfree(dev); } static void _enqueue_ping(Device * dev, struct timeval *timeout) { struct timeval timeleft; if (dev->scripts[PM_PING] != NULL && timerisset(&dev->ping_period)) { if (_timeout(&dev->last_ping, &dev->ping_period, &timeleft)) { _enqueue_actions(dev, PM_PING, NULL, NULL, NULL, NULL, 0, NULL); if (gettimeofday(&dev->last_ping, NULL) < 0) err_exit(true, "gettimeofday"); dbg(DBG_ACTION, "%s: enqeuuing ping", dev->name); } else _update_timeout(timeout, &timeleft); } } /* * Called prior to the select loop to initiate connects to all devices. */ void dev_initial_connect(void) { Device *dev; ListIterator itr; itr = list_iterator_create(dev_devices); while ((dev = list_next(itr))) { assert(dev->connect_state == DEV_NOT_CONNECTED); _connect(dev); } list_iterator_destroy(itr); } /* * Select says device is ready for reading. */ static bool _handle_read(Device * dev) { int n; int dropped; n = cbuf_write_from_fd(dev->from, dev->fd, -1, &dropped); if (n < 0) { err(true, "read error on %s", dev->name); goto err; } if (n == 0) { dbg(DBG_DEVICE, "read returned EOF on %s", dev->name); goto err; } if (dropped > 0) err(false, "%s lost %d chars due to buffer wrap", dev->name, dropped); return false; err: return true; } /* * Select says device is ready for writing. */ static bool _handle_write(Device * dev) { int n; n = cbuf_read_to_fd(dev->to, dev->fd, -1); if (n < 0) { err(true, "write error on %s", dev->name); goto err; } if (n == 0) { err(false, "write sent no data on %s", dev->name); goto err; } return false; err: return true; } /* One of the poll bits is set for the device - handle it! */ static bool _handle_ready_device(Device *dev, short flags) { assert(dev->connect_state != DEV_NOT_CONNECTED); assert(dev->fd != NO_FD); /* error cases (won't get here with select - only poll) */ if (flags & XPOLLHUP) { err(false, "%s: poll: hangup", dev->name); goto ioerr; } if (flags & XPOLLERR) { err(false, "%s: poll: error", dev->name); goto ioerr; } if (flags & XPOLLNVAL) { err(false, "%s: poll: fd not open", dev->name); goto ioerr; } /* ready for writing */ if (flags & XPOLLOUT) { if (dev->connect_state == DEV_CONNECTING) { assert(dev->finish_connect != NULL); if (!dev->finish_connect(dev)) goto ioerr; if (dev->connect_state == DEV_CONNECTED) _enqueue_login(dev); /* enqueue login if connected */ goto success; /* don't want to test read bit */ } else { assert(dev->connect_state == DEV_CONNECTED); if (_handle_write(dev)) goto ioerr; } } /* ready for reading */ if (flags & XPOLLIN) { if (_handle_read(dev)) goto ioerr; if (dev->preprocess != NULL) dev->preprocess(dev); /* preprocess input, e.g. telnet escapes */ } success: return false; ioerr: return true; } /* * Called before poll to ready pfd. */ void dev_pre_poll(xpollfd_t pfd) { Device *dev; ListIterator itr; itr = list_iterator_create(dev_devices); while ((dev = list_next(itr))) { short flags = 0; if (dev->fd < 0) continue; /* always set read set bits so select will unblock if the * connection is dropped. */ flags |= XPOLLIN; /* need to be in the write set if we are sending anything */ if (dev->connect_state == DEV_CONNECTED) { if (!cbuf_is_empty(dev->to)) flags |= XPOLLOUT; } /* descriptor will become writable after a connect */ if (dev->connect_state == DEV_CONNECTING) flags |= XPOLLOUT; xpollfd_set(pfd, dev->fd, flags); } list_iterator_destroy(itr); } /* * Called after select to process ready file descriptors, timeouts, etc. */ void dev_post_poll(xpollfd_t pfd, struct timeval *timeout) { Device *dev; ListIterator itr; itr = list_iterator_create(dev_devices); while ((dev = list_next(itr))) { short flags = dev->fd != NO_FD ? xpollfd_revents(pfd, dev->fd) : 0; bool ioerr = false; /* A device is "ready", e.g. it can be read/written or has an error */ if (flags) ioerr = _handle_ready_device(dev, flags); /* Either initiate reconnect or recalculate timeout (for backoff) * so poll will unblock then. If successful, _reconnect() * will enqueue a login action which will need processing below. */ if (ioerr || dev->connect_state == DEV_NOT_CONNECTED) _reconnect(dev, timeout); /* can update dev->connect_state */ /* If we are periodically "pinging" this device, we may need to * enqueue a ping action, or update the timeout so poll will * unblock when it is time to enqueue one. */ if (dev->connect_state == DEV_CONNECTED) _enqueue_ping(dev, timeout); /* If any actions are enqueued, process them. This is state machine * activity and I/O to/from cbufs, not device I/O. Update timeout so * poll will unblock to handle non-responsive devices, or processing * of scripted delays. Note that we are not necessarily connected * to the device - users may enqueue actions on an unconnected device, * which expedites a reconnect; if the reconnect then times out, * we have to time out the actions (e.g. tell the user). */ _process_action(dev, timeout); } list_iterator_destroy(itr); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/device.h000066400000000000000000000012711467035776500174250ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_DEVICE_H #define PM_DEVICE_H void dev_init(bool short_circuit_delay); void dev_fini(void); void dev_initial_connect(void); void dev_pre_poll(xpollfd_t pfd); void dev_post_poll(xpollfd_t pfd, struct timeval *tv); #endif /* PM_DEVICE_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/device_pipe.c000066400000000000000000000103071467035776500204350ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2003 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* * Implement connect/disconnect device methods for coprocess on a socketpair. */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include "hostlist.h" #include "list.h" #include "cbuf.h" #include "parse_util.h" #include "xmalloc.h" #include "xpoll.h" #include "pluglist.h" #include "arglist.h" #include "xregex.h" #include "device_private.h" #include "device_pipe.h" #include "error.h" #include "debug.h" #include "argv.h" #include "fdutil.h" typedef struct { char **argv; pid_t cpid; } PipeDev; /* Create "pipe device" data struct. * cmdline would normally look something like "/usr/bin/conman -j -Q bay0 |&" * (Korn shell style "coprocess" syntax) */ void *pipe_create(char *cmdline, char *flags) { PipeDev *pd = (PipeDev *)xmalloc(sizeof(PipeDev)); pd->argv = argv_create(cmdline, "|&"); pd->cpid = -1; return (void *)pd; } /* Destroy pipe device data struct. */ void pipe_destroy(void *data) { PipeDev *pd = (PipeDev *)data; argv_destroy(pd->argv); xfree(pd); } /* Start the coprocess. */ bool pipe_connect(Device * dev) { int fd[2]; pid_t pid; PipeDev *pd = (PipeDev *)dev->data; assert(dev->connect_state == DEV_NOT_CONNECTED); assert(dev->fd == NO_FD); if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fd) < 0) err_exit(true, "_pipe_connect(%s): socketpair", dev->name); pid = fork(); if (pid < 0) { err_exit(true, "_pipe_connect(%s): fork", dev->name); } else if (pid == 0) { /* child */ (void)dup2(fd[1], STDIN_FILENO); (void)dup2(fd[1], STDOUT_FILENO); (void)close(fd[1]); (void)close(fd[0]); execv(pd->argv[0], pd->argv); err_exit(true, "exec %s", pd->argv[0]); } else { /* parent */ (void)close(fd[1]); nonblock_set(fd[0]); dev->fd = fd[0]; dev->connect_state = DEV_CONNECTED; dev->stat_successful_connects++; pd->cpid = pid; dbg(DBG_DEVICE, "_pipe_connect(%s): opened", dev->name); } return (dev->connect_state == DEV_CONNECTED); } /* * Close down the socketpair. */ void pipe_disconnect(Device * dev) { PipeDev *pd = (PipeDev *)dev->data; assert(dev->connect_state == DEV_CONNECTED); dbg(DBG_DEVICE, "_pipe_disconnect: %s on fd %d", dev->name, dev->fd); if (dev->fd >= 0) { if (close(dev->fd) < 0) err(true, "_pipe_disconnect: %s close fd %d", dev->name, dev->fd); dev->fd = NO_FD; } /* reap child */ if (pd->cpid > 0) { int wstat; kill(pd->cpid, SIGTERM); /* ignore errors */ if (waitpid(pd->cpid, &wstat, 0) < 0) err(true, "_pipe_disconnect(%s): wait", dev->name); if (WIFEXITED(wstat)) { if (WEXITSTATUS(wstat) == 0) dbg(DBG_DEVICE, "_pipe_disconnect(%s): %s exited with status 0", dev->name, pd->argv[0]); else err(false, "_pipe_disconnect(%s): %s exited with status %d", dev->name, pd->argv[0], WEXITSTATUS(wstat)); } else if (WIFSIGNALED(wstat)) { if (WTERMSIG(wstat) == SIGTERM) dbg(DBG_DEVICE, "_pipe_disconnect(%s): %s terminated", dev->name, pd->argv[0]); else err(false, "_pipe_disconnect(%s): %s terminated with signal %d", dev->name, pd->argv[0], WTERMSIG(wstat)); } else { err(false, "_pipe_disconnect(%s): %s terminated", dev->name, pd->argv[0]); } pd->cpid = -1; } } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/device_pipe.h000066400000000000000000000012431467035776500204410ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2003 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_DEVICE_PIPE_H #define PM_DEVICE_PIPE_H bool pipe_connect(Device * dev); void pipe_disconnect(Device * dev); void *pipe_create(char *cmdline, char *flags); void pipe_destroy(void *data); #endif /* PM_DEVICE_PIPE_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/device_private.h000066400000000000000000000136051467035776500211630ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_DEVICE_PRIVATE_H #define PM_DEVICE_PRIVATE_H #define NO_FD (-1) /* Indices into script array */ #define PM_LOG_IN 0 #define PM_LOG_OUT 1 #define PM_STATUS_PLUGS 2 #define PM_STATUS_PLUGS_ALL 3 /*4*/ /*5*/ #define PM_PING 6 #define PM_POWER_ON 7 #define PM_POWER_ON_RANGED 8 #define PM_POWER_ON_ALL 9 #define PM_POWER_OFF 10 #define PM_POWER_OFF_RANGED 11 #define PM_POWER_OFF_ALL 12 #define PM_POWER_CYCLE 13 #define PM_POWER_CYCLE_RANGED 14 #define PM_POWER_CYCLE_ALL 15 #define PM_RESET 16 #define PM_RESET_RANGED 17 #define PM_RESET_ALL 18 #define PM_STATUS_TEMP 19 #define PM_STATUS_TEMP_ALL 20 #define PM_STATUS_BEACON 21 #define PM_STATUS_BEACON_ALL 22 #define PM_BEACON_ON 23 #define PM_BEACON_ON_RANGED 24 #define PM_BEACON_OFF 25 #define PM_BEACON_OFF_RANGED 26 #define PM_RESOLVE 27 #define NUM_SCRIPTS 28 /* count of scripts above */ #define MAX_MATCH_POS 20 typedef struct { InterpState state; char *str; xregex_t re; } StateInterp; typedef struct { InterpResult result; char *str; xregex_t re; } ResultInterp; /* * A Script is a list of Stmts. */ typedef enum { STMT_SEND, STMT_EXPECT, STMT_SETPLUGSTATE, STMT_SETRESULT, STMT_DELAY, STMT_FOREACHPLUG, STMT_FOREACHNODE, STMT_IFOFF, STMT_IFON, } StmtType; typedef struct { StmtType type; union { struct { /* SEND */ char *fmt; /* printf(fmt, ...) style format string */ } send; struct { /* EXPECT */ xregex_t exp; /* compiled regex */ } expect; struct { /* SETPLUGSTATE (regexs refer to prev expect) */ char *plug_name; /* plug name if literally specified */ int plug_mp; /* regex subexp match pos of plug name if not */ int stat_mp; /* regex subexp match pos of plug status */ List interps; /* list of possible interpretations */ } setplugstate; struct { /* SETRESULT (regexs refer to prev expect) */ int plug_mp; /* regex subexp match pos of plug name if not */ int stat_mp; /* regex subexp match pos of plug status */ List interps; /* list of possible interpretations */ } setresult; struct { /* DELAY */ struct timeval tv; /* delay at this point in the script */ } delay; struct { /* FOREACHPLUG | FOREACHNODE */ List stmts; /* list of statements to exec in a loop */ } foreach; struct { /* IFON | IFOFF */ List stmts; /* list of statements to exec conditionally */ } ifonoff; } u; } Stmt; typedef List Script; /* * Device */ typedef enum { DEV_NOT_CONNECTED, DEV_CONNECTING, DEV_CONNECTED } ConnectState; typedef struct _device { char *name; /* name of device */ char *specname; /* name of specification, e.g. "icebox3" */ ConnectState connect_state; /* is device connected/open? */ bool logged_in; /* true if login script has run successfully */ xregex_match_t xmatch; /* cache regex matches for future $N ref */ int fd; /* socket, serial device, or pty */ List acts; /* queue of Actions */ struct timeval timeout; /* configurable device timeout */ cbuf_t to; /* buffer -> device */ cbuf_t from; /* buffer <- device */ PlugList plugs; /* list of Plugs (node name <-> plug name) */ Script scripts[NUM_SCRIPTS]; /* array of scripts */ struct timeval last_retry; /* time of last reconnect retry */ int retry_count; /* number of retries attempted */ struct timeval last_ping; /* time of last ping (if any) */ struct timeval ping_period; /* configurable ping period (0.0 = none) */ int stat_successful_connects; int stat_successful_actions; /* network (e.g. tcp/serial)-specific methods */ bool (*connect)(struct _device *dev); bool (*finish_connect)(struct _device *dev); void (*preprocess)(struct _device *dev); void (*disconnect)(struct _device *dev); void (*destroy)(void *data); void *data; } Device; typedef enum { ACT_ESUCCESS, ACT_EEXPFAIL, ACT_EABORT, ACT_ECONNECTTIMEOUT, ACT_ELOGINTIMEOUT } ActError; typedef void (*ActionCB) (int client_id, ActError acterr, const char *fmt, ...) __attribute__ ((format (printf, 3, 4))); typedef void (*VerbosePrintf) (int client_id, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); typedef void (*DiagPrintf) (int client_id, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); #define MIN_DEV_BUF 1024 #define MAX_DEV_BUF 1024*64 void dev_add(Device * dev); int dev_enqueue_actions(int com, hostlist_t hl, ActionCB complete_fun, VerbosePrintf vpf_fun, DiagPrintf dpf_fun, int client_id, ArgList arglist); bool dev_check_actions(int com, hostlist_t hl); Device *dev_create(const char *name); void dev_destroy(Device * dev); Device *dev_findbyname(char *name); List dev_getdevices(void); #endif /* PM_DEVICE_PRIVATE_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/device_serial.c000066400000000000000000000145411467035776500207630ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2003 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* * Implement connect/disconnect device methods for serial devices. */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include "cbuf.h" #include "hostlist.h" #include "list.h" #include "parse_util.h" #include "xpoll.h" #include "xmalloc.h" #include "pluglist.h" #include "arglist.h" #include "xregex.h" #include "device_private.h" #include "device_serial.h" #include "error.h" #include "debug.h" #include "fdutil.h" typedef struct { char *special; char *flags; } SerialDev; typedef struct { int baud; speed_t bconst; } baudmap_t; static baudmap_t baudmap[] = { {300, B300}, {1200, B1200}, {2400, B2400}, {4800, B4800}, {9600, B9600}, {19200, B19200}, {38400, B38400}, #ifdef B57600 {57600, B57600}, #endif #ifdef B115200 {115200,B115200}, #endif #ifdef B230400 {230400,B230400}, #endif #ifdef B460800 {460800,B460800}, #endif }; void *serial_create(char *special, char *flags) { SerialDev *ser = (SerialDev *)xmalloc(sizeof(SerialDev)); ser->special = xstrdup(special); ser->flags = xstrdup(flags); return (void *)ser; } void serial_destroy(void *data) { SerialDev *ser = (SerialDev *)data; if (ser->special) xfree(ser->special); if (ser->flags) xfree(ser->flags); xfree(ser); } /* Set up serial port: 0 on success, <0 on error */ static int _serial_setup(char *devname, int fd, int baud, int databits, char parity, int stopbits) { int res; struct termios tio; int i; res = tcgetattr(fd, &tio); if (res < 0) { err(true, "%s: error getting serial attributes", devname); return -1; } res = -1; for (i = 0; i < sizeof(baudmap)/sizeof(baudmap_t); i++) { if (baudmap[i].baud == baud) { if ((res = cfsetispeed(&tio, baudmap[i].bconst)) == 0) res = cfsetospeed(&tio, baudmap[i].bconst); break; } } if (res < 0) { err(false, "%s: error setting baud rate to %d", devname, baud); return -1; } switch (databits) { case 7: tio.c_cflag &= ~CSIZE; tio.c_cflag |= CS7; break; case 8: tio.c_cflag &= ~CSIZE; tio.c_cflag |= CS8; break; default: err(false, "%s: error setting data bits to %d", devname, databits); return -1; } switch (stopbits) { case 1: tio.c_cflag &= ~CSTOPB; break; case 2: tio.c_cflag |= CSTOPB; break; default: err(false, "%s: error setting stop bits to %d", devname, stopbits); return -1; } switch (parity) { case 'n': case 'N': tio.c_cflag &= ~PARENB; break; case 'e': case 'E': tio.c_cflag |= PARENB; tio.c_cflag &= ~PARODD; break; case 'o': case 'O': tio.c_cflag |= PARENB; tio.c_cflag |= PARODD; break; default: err(false, "%s: error setting parity to %c", devname, parity); return -1; } tio.c_oflag &= ~OPOST; /* turn off post-processing of output */ tio.c_iflag = tio.c_lflag = 0; if (tcsetattr(fd, TCSANOW, &tio) < 0) { err(true, "%s: error setting serial attributes", devname); return -1; } return 0; } /* * Open the special file associated with this device. */ bool serial_connect(Device * dev) { SerialDev *ser; int baud = 9600, databits = 8, stopbits = 1; char parity = 'N'; int res; int n; assert(dev->connect_state == DEV_NOT_CONNECTED); assert(dev->fd == NO_FD); ser = (SerialDev *)dev->data; dev->fd = open(ser->special, O_RDWR | O_NONBLOCK | O_NOCTTY); if (dev->fd < 0) { err(true, "_serial_connect(%s): open %s", dev->name, ser->special); goto out; } if (!isatty(dev->fd)) { err(false, "_serial_connect(%s): not a tty", dev->name); goto out; } /* [lifted from conman] According to the UNIX Programming FAQ v1.37 * * (Section 3.6: How to Handle a Serial Port or Modem), * systems seem to differ as to whether a nonblocking * open on a tty will affect subsequent read()s. * Play it safe and be explicit! */ nonblock_set(dev->fd); /* Conman takes an fcntl F_WRLCK on serial devices. * Powerman should respect conman's locks and vice-versa. */ if (lockf(dev->fd, F_TLOCK, 0) < 0) { err(true, "_serial_connect(%s): could not lock device\n", dev->name); goto out; } /* parse the serial flags and set up port accordingly */ n = sscanf(ser->flags, "%d,%d%c%d", &baud, &databits, &parity, &stopbits); assert(n >= 0 && n <= 4); /* 0-4 matches OK (defaults if no match) */ res = _serial_setup(dev->name, dev->fd, baud, databits, parity, stopbits); if (res < 0) goto out; dev->connect_state = DEV_CONNECTED; dev->stat_successful_connects++; dbg(DBG_DEVICE, "_serial_connect(%s): opened", dev->name); return true; out: if (dev->fd >= 0) { if (close(dev->fd) < 0) err(true, "_serial_connect(%s): close", dev->name); dev->fd = NO_FD; } return false; } /* * Close the special file associated with this device. */ void serial_disconnect(Device * dev) { assert(dev->connect_state == DEV_CONNECTED); dbg(DBG_DEVICE, "_serial_disconnect: %s on fd %d", dev->name, dev->fd); /* close device if open */ if (dev->fd >= 0) { if (close(dev->fd) < 0) err(true, "_serial_disconnect(%s): close", dev->name); dev->fd = NO_FD; } dbg(DBG_DEVICE, "_serial_disconnect(%s): closed", dev->name); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/device_serial.h000066400000000000000000000012611467035776500207630ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2003 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_DEVICE_SERIAL_H #define PM_DEVICE_SERIAL_H bool serial_connect(Device * dev); void serial_disconnect(Device * dev); void *serial_create(char *special, char *flags); void serial_destroy(void *data); #endif /* PM_DEVICE_SERIAL_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/device_tcp.c000066400000000000000000000307371467035776500202770ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* * Implement connect/disconnect/preprocess methods for tcp/telnet devices. * * NOTE: we always do telnet when we are doing tcp. If there ever is a telnet * device that requires some proactive option negotiation, or a non-telnet * device that manages to confuse the telnet state machine, we could easily * implement a 'notelnet' flag. Right now it seems innocuous to leave the * telnet machine running. */ #if HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include #include #define TELOPTS #define TELCMDS #include #include #include "list.h" #include "hostlist.h" #include "cbuf.h" #include "parse_util.h" #include "xmalloc.h" #include "xpoll.h" #include "pluglist.h" #include "arglist.h" #include "xregex.h" #include "device_private.h" #include "error.h" #include "debug.h" #include "device_tcp.h" #include "fdutil.h" #ifndef HAVE_SOCKLEN_T typedef int socklen_t; /* socklen_t is uint32_t in Posix.1g */ #endif /* !HAVE_SOCKLEN_T */ typedef enum { TELNET_NONE, TELNET_CMD, TELNET_OPT } TelnetState; typedef struct { char *host; char *port; TelnetState tstate; /* state of telnet processing */ unsigned char tcmd; /* buffered telnet command */ bool quiet; /* don't report idle timeout messages */ struct addrinfo *addrs; struct addrinfo *cur; } TcpDev; static void _telnet_init(Device *dev); static void _telnet_preprocess(Device * dev); static void _parse_options(TcpDev *tcp, char *flags) { char *tmp = xstrdup(flags); char *opt = strtok(tmp, ","); while (opt) { if (strcmp(opt, "quiet") == 0) tcp->quiet = true; else err_exit(false, "bad device option: %s\n", opt); opt = strtok(NULL, ","); } xfree(tmp); } void *tcp_create(char *host, char *port, char *flags) { TcpDev *tcp = (TcpDev *)xmalloc(sizeof(TcpDev)); struct addrinfo hints; int error; tcp->host = xstrdup(host); tcp->port = xstrdup(port); tcp->tstate = TELNET_NONE; tcp->tcmd = 0; tcp->quiet = false; if (flags) _parse_options(tcp, flags); /* Store a list of possible addresses/families to connect to * in the tcp->addrs linked list. */ memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if ((error = getaddrinfo(tcp->host, tcp->port, &hints, &tcp->addrs)) != 0) err_exit(false, "getaddrinfo %s:%s: %s", tcp->host, tcp->port, gai_strerror(error)); if (tcp->addrs == NULL) err_exit(false, "no addresses for server %s:%s", tcp->host, tcp->port); tcp->cur = tcp->addrs; return (void *)tcp; } void tcp_destroy(void *data) { TcpDev *tcp = (TcpDev *)data; if (tcp->host) xfree(tcp->host); if (tcp->port) xfree(tcp->port); if (tcp->addrs) freeaddrinfo(tcp->addrs); xfree(tcp); } /* After a successful connect, perform some management on * the connection. Returns true on success, false on error. */ static bool tcp_finish_connect_one(Device *dev) { int rc; int error = 0; socklen_t len = sizeof(error); rc = getsockopt(dev->fd, SOL_SOCKET, SO_ERROR, &error, &len); /* * If an error occurred, Berkeley-derived implementations * return 0 with the pending error in 'error'. But Solaris * returns -1 with the pending error in 'errno'. -dun */ if (rc < 0) error = errno; if (! error) { dev->connect_state = DEV_CONNECTED; dev->stat_successful_connects++; _telnet_init(dev); return true; } return false; } /* Obtain a socket for the specified address and attempt to connect it. * Return true on completion or connection in progress, false on error. */ static bool tcp_connect_one(Device *dev, struct addrinfo *addr) { TcpDev *tcp = (TcpDev *)dev->data; int opt; assert(tcp->cur != NULL); if ((dev->fd = socket(addr->ai_family, addr->ai_socktype, 0)) < 0) return false; opt = 1; if (setsockopt(dev->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { close(dev->fd); return false; } nonblock_set(dev->fd); if (connect(dev->fd, addr->ai_addr, addr->ai_addrlen) >= 0) return tcp_finish_connect_one(dev); else if (errno == EINPROGRESS) return true; close(dev->fd); return false; } /* * Continue TCP connect when fd unblocks. * Return false on error, which triggers timed retry of tcp_connect(). * Return true if connected or still connecting (on the next address). */ bool tcp_finish_connect(Device * dev) { TcpDev *tcp; assert(dev->connect_state == DEV_CONNECTING); tcp = (TcpDev *)dev->data; if (!tcp_finish_connect_one(dev)) { tcp->cur = tcp->cur->ai_next; while (tcp->cur && !tcp_connect_one(dev, tcp->cur)) tcp->cur = tcp->cur->ai_next; if (tcp->cur == NULL) dev->connect_state = DEV_NOT_CONNECTED; } switch(dev->connect_state) { case DEV_NOT_CONNECTED: err(false, "tcp_finish_connect(%s): connection refused", dev->name); break; case DEV_CONNECTED: dbg(DBG_DEVICE, "tcp_finish_connect(%s): connected", dev->name); break; case DEV_CONNECTING: dbg(DBG_DEVICE, "tcp_finish_connect(%s): connecting", dev->name); break; } return (dev->connect_state != DEV_NOT_CONNECTED); } /* * Initiate a non-blocking TCP connect. tcp_finish_connect() will try to * finish the job when the main poll() loop unblocks again, unless we * finish here. */ bool tcp_connect(Device * dev) { TcpDev *tcp; assert(dev->connect_state == DEV_NOT_CONNECTED); assert(dev->fd == NO_FD); tcp = (TcpDev *)dev->data; dev->connect_state = DEV_CONNECTING; while (tcp->cur && !tcp_connect_one(dev, tcp->cur)) tcp->cur = tcp->cur->ai_next; if (tcp->cur == NULL) dev->connect_state = DEV_NOT_CONNECTED; switch(dev->connect_state) { case DEV_NOT_CONNECTED: err(false, "tcp_connect(%s): connection refused", dev->name); break; case DEV_CONNECTED: dbg(DBG_DEVICE, "tcp_connect(%s): connected", dev->name); break; case DEV_CONNECTING: dbg(DBG_DEVICE, "tcp_connect(%s): connecting", dev->name); break; } return (dev->connect_state == DEV_CONNECTED); } /* * Close the socket associated with this device. */ void tcp_disconnect(Device * dev) { assert(dev->connect_state == DEV_CONNECTING || dev->connect_state == DEV_CONNECTED); dbg(DBG_DEVICE, "tcp_disconnect: %s on fd %d", dev->name, dev->fd); /* close socket if open */ if (dev->fd >= 0) { if (close(dev->fd) < 0) err(true, "tcp_disconnect: %s close fd %d", dev->name, dev->fd); dev->fd = NO_FD; } dbg(DBG_DEVICE, "tcp_disconnect(%s): disconnected", dev->name); } void tcp_preprocess(Device *dev) { _telnet_preprocess(dev); } static void _telnet_sendopt(Device *dev, int cmd, int opt) { unsigned char str[] = { IAC, cmd, opt }; int n; dbg(DBG_TELNET, "%s: _telnet_sendopt: %s %s", dev->name, TELCMD_OK(cmd) ? TELCMD(cmd) : "", TELOPT_OK(opt) ? TELOPT(opt) : ""); n = cbuf_write(dev->to, str, 3, NULL); if (n < 3) err((n < 0), "_telnet_sendopt: cbuf_write returned %d", n); } #if 0 static void _telnet_sendcmd(Device *dev, unsigned char cmd) { unsigned char str[] = { IAC, cmd }; int n; dbg(DBG_TELNET, "%s: _telnet_sendcmd: %s", dev->name, TELCMD_OK(cmd) ? TELCMD(cmd) : ""); n = cbuf_write(dev->to, str, 2, NULL); if (n < 2) err((n < 0), "_telnet_sendcmd: cbuf_write returned %d", n); } #endif static void _telnet_recvcmd(Device *dev, int cmd) { dbg(DBG_TELNET, "%s: _telnet_recvcmd: %s", dev->name, TELCMD_OK(cmd) ? TELCMD(cmd) : ""); } static void _telnet_recvopt(Device *dev, int cmd, int opt) { TcpDev *tcp = (TcpDev *)dev->data; dbg(DBG_TELNET, "%s: _telnet_recvopt: %s %s", dev->name, TELCMD_OK(cmd) ? TELCMD(cmd) : "", TELOPT_OK(opt) ? TELOPT(opt) : ""); switch (cmd) { case DO: switch (opt) { case TELOPT_SGA: /* rfc 858 - suppress go ahead*/ case TELOPT_TM: /* rfc 860 - timing mark */ _telnet_sendopt(dev, WILL, opt); break; case TELOPT_TTYPE: /* rfc 1091 - terminal type */ case TELOPT_NAWS: /* rfc 1073 - window size */ /* next three added for gnat powerman/634 - jg */ case TELOPT_NEW_ENVIRON: /* environment variables */ case TELOPT_XDISPLOC: /* X display location */ case TELOPT_TSPEED: /* terminal speed */ /* next two added for newer baytechs - jg */ case TELOPT_ECHO: /* echo */ case TELOPT_LFLOW: /* remote flow control */ /* next one added for cyclades ts - jg */ case TELOPT_BINARY: /* 8-bit data path */ _telnet_sendopt(dev, WONT, opt); break; default: if (!tcp->quiet) err(0, "%s: _telnet_recvopt: ignoring %s %s", dev->name, TELCMD_OK(cmd) ? TELCMD(cmd) : "", TELOPT_OK(opt) ? TELOPT(opt) : ""); break; } break; default: break; } } /* * Called just after a connect so we can perform any option requests. */ static void _telnet_init(Device * dev) { TcpDev *tcp = (TcpDev *)dev->data; tcp->tstate = TELNET_NONE; tcp->tcmd = 0; #if 0 _telnet_sendopt(dev, DONT, TELOPT_NAWS); _telnet_sendopt(dev, DONT, TELOPT_TTYPE); _telnet_sendopt(dev, DONT, TELOPT_ECHO); #endif } /* * Telnet state machine. This is called when new data has arrived in the * input buffer. We get to look first to process any telnet escapes. * Except for a little bit of state stored in the dev->u.tcp union, * we do all the processing now. */ static void _telnet_preprocess(Device * dev) { static unsigned char peek[MAX_DEV_BUF]; static unsigned char device[MAX_DEV_BUF]; TcpDev *tcp = (TcpDev *)dev->data; int len, i, k; len = cbuf_peek(dev->from, peek, MAX_DEV_BUF); for (i = 0, k = 0; i < len; i++) { switch (tcp->tstate) { case TELNET_NONE: if (peek[i] == IAC) tcp->tstate = TELNET_CMD; else device[k++] = peek[i]; break; case TELNET_CMD: switch (peek[i]) { case IAC: /* escaped IAC */ device[k++] = peek[i]; tcp->tstate = TELNET_NONE; break; case DONT: /* option commands - one more byte coming */ case DO: case WILL: case WONT: tcp->tcmd = peek[i]; tcp->tstate = TELNET_OPT; break; default: /* single char commands - process immediately */ _telnet_recvcmd(dev, peek[i]); tcp->tstate = TELNET_NONE; break; } break; case TELNET_OPT: /* option char - process stored command */ _telnet_recvopt(dev, tcp->tcmd, peek[i]); tcp->tstate = TELNET_NONE; break; } } /* rewrite buffers if anything changed */ if (k < len) { int n; n = cbuf_drop(dev->from, len); if (n < len) err((n < 0), "_telnet_preprocess: cbuf_drop returned %d", n); n = cbuf_write(dev->from, device, k, NULL); if (n < k) err((n < 0), "_telnet_preprocess: cbuf_write returned %d", n); } } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/device_tcp.h000066400000000000000000000013601467035776500202720ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_DEVICE_TCP_H #define PM_DEVICE_TCP_H bool tcp_finish_connect(Device * dev); bool tcp_connect(Device * dev); void tcp_disconnect(Device * dev); void tcp_preprocess(Device * dev); void *tcp_create(char *host, char *port, char *flags); void tcp_destroy(void *data); #endif /* PM_DEVICE_TCP_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/libpowerman.c000066400000000000000000000370571467035776500205130ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2008 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* * libpowerman.c - simple powerman client library */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include "client_proto.h" #include "libpowerman.h" #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif #ifndef MAXPORTNAMELEN #define MAXPORTNAMELEN 64 #endif struct pm_handle_struct { int pmh_fd; }; typedef void (*list_free_t) (void *x); struct list_struct { char * data; struct list_struct *next; list_free_t freefun; }; struct pm_node_iterator_struct { struct list_struct *pmi_nodes; struct list_struct *pmi_pos; }; static pm_err_t _list_add(struct list_struct **head, char *s, list_free_t freefun); static void _list_free(struct list_struct **head); static int _list_search(struct list_struct *head, char *s); static int _strncmpend(char *s1, char *s2, int len); static char * _strndup(char *s, int len); static void _parse_hostport(char *s, char *host, char *port); static pm_err_t _connect_to_server_tcp(pm_handle_t pmh, char *server, int family); static pm_err_t _parse_response(char *buf, int len, struct list_struct **respp); static pm_err_t _server_recv_response(pm_handle_t pmh, struct list_struct **respp); static pm_err_t _server_send_command(pm_handle_t pmh, char *cmd, char *arg); static pm_err_t _server_command(pm_handle_t pmh, char *cmd, char *arg, struct list_struct **respp); /* Add [s] to the list referenced by [head], registering [freefun] to * be called on [s] when the list is freed. */ static pm_err_t _list_add(struct list_struct **head, char *s, list_free_t freefun) { struct list_struct *new; if (!(new = malloc(sizeof(struct list_struct)))) return PM_ENOMEM; new->data = s; new->next = *head; new->freefun = freefun; *head = new; return PM_ESUCCESS; } /* Free the list referred to by [head]. */ static void _list_free(struct list_struct **head) { struct list_struct *lp, *tmp; for (lp = *head; lp != NULL; lp = tmp) { tmp = lp->next; if (lp->freefun) lp->freefun(lp->data); free(lp); } *head = NULL; } /* Scan the list referenced by [head] looking for an element containing * exactly the string [s], returning true if found. */ static int _list_search(struct list_struct *head, char *s) { struct list_struct *lp; for (lp = head; lp != NULL; lp = lp->next) if (strcmp(lp->data, s) == 0) return 1; return 0; } /* Test if [s2] is a terminating substring of [s1]. */ static int _strncmpend(char *s1, char *s2, int len) { return strncmp(s1 + len - strlen(s2), s2, strlen(s2)); } /* Duplicate string [s] of length [len]. * Result will be NULL terminated. [s] doesn't have to be. */ static char * _strndup(char *s, int len) { char *c; if ((c = (char *)malloc(len + 1))) { memcpy(c, s, len); c[len] = '\0'; } return c; } static void _parse_hostport(char *s, char *host, char *port) { char *p; if (s) snprintf(host, MAXHOSTNAMELEN, "%s", s); else snprintf(host, MAXHOSTNAMELEN, "%s", PM_DFLT_HOST); if ((p = strchr(host, ':'))) { *p++ = '\0'; snprintf(port, MAXPORTNAMELEN, "%s", p); } else snprintf(port, MAXPORTNAMELEN, "%s", PM_DFLT_PORT); } /* Establish connection to powermand [server]. * Connection state is returned in the handle. */ static pm_err_t _connect_to_server_tcp(pm_handle_t pmh, char *server, int family) { struct addrinfo hints, *res, *r; pm_err_t err = PM_ECONNECT; char host[MAXHOSTNAMELEN], port[MAXPORTNAMELEN]; memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; _parse_hostport(server, host, port); if (getaddrinfo(host, port, &hints, &res) != 0 || res == NULL) return PM_ENOADDR; for (r = res; r != NULL; r = r->ai_next) { if ((pmh->pmh_fd = socket(r->ai_family, r->ai_socktype, 0)) < 0) continue; if (connect(pmh->pmh_fd, r->ai_addr, r->ai_addrlen) < 0) { close(pmh->pmh_fd); continue; } err = PM_ESUCCESS; break; } freeaddrinfo(res); return err; } /* Parse a server response stored in [buf] of length [len] into * an array of lines stored in [respp] which caller must free. */ static pm_err_t _parse_response(char *buf, int len, struct list_struct **respp) { int i, l = strlen(CP_EOL); char *p, *cpy; struct list_struct *resp = NULL; pm_err_t err = PM_ESUCCESS; p = buf; for (i = 0; i < len - l; i++) { if (strncmp(&buf[i], CP_EOL, l) != 0) continue; if ((cpy = _strndup(p, &buf[i] - p + l)) == NULL) { err = PM_ENOMEM; break; } if ((err = _list_add(&resp, cpy, (list_free_t)free)) != PM_ESUCCESS) break; p = &buf[i + l]; } if (err == PM_ESUCCESS && respp != NULL) *respp = resp; else _list_free(&resp); return err; } /* Scan response from server for return code. */ static pm_err_t _server_retcode(struct list_struct *resp) { int code; pm_err_t err = PM_ESERVERPARSE; /* N.B. there will only be one 1xx or 2xx code in a response */ while (resp != NULL) { if (sscanf(resp->data, "%d ", &code) == 1) { switch (code) { case 1: /* hello */ case 101: /* goodbye */ case 102: /* command completed successfully */ case 103: /* query complete */ case 104: /* telemetry on|off */ case 105: /* hostrange expansion on|off */ err = PM_ESUCCESS; break; case PM_EUNKNOWN: case PM_EPARSE: case PM_ETOOLONG: case PM_EINTERNAL: case PM_EHOSTLIST: case PM_EINPROGRESS: case PM_ENOSUCHNODES: case PM_ECOMMAND: case PM_EQUERY: case PM_EUNIMPL: err = code; break; default: /* 3xx informational (ignore) */ break; } } resp = resp->next; } return err; } /* Read response from server handle [pmh] and store it in * [resp], an array of lines. Caller must free [resp]. */ static pm_err_t _server_recv_response(pm_handle_t pmh, struct list_struct **respp) { int buflen = 0, count = 0, n; char *buf = NULL; pm_err_t err = PM_ESUCCESS; struct list_struct *resp; do { if (buflen - count == 0) { buflen += CP_LINEMAX; buf = buf ? realloc(buf, buflen) : malloc(buflen); if (buf == NULL) { err = PM_ENOMEM; break; } } n = read(pmh->pmh_fd, buf + count, buflen - count); if (n == 0) { err = PM_ESERVEREOF; break; } if (n < 0) { err = PM_ERRNOVALID; break; } count += n; } while (_strncmpend(buf, CP_PROMPT, count) != 0); if (err == PM_ESUCCESS) { err = _parse_response(buf, count, &resp); if (err == PM_ESUCCESS) { err = _server_retcode(resp); if (err == PM_ESUCCESS && respp != NULL) *respp = resp; else _list_free(&resp); } } if (buf != NULL) free(buf); return err; } /* Send command [cmd] with argument [arg] to server handle [pmh]. * [cmd] is treated as a printf format string with [arg] as the * first printf argument (can be NULL). */ static pm_err_t _server_send_command(pm_handle_t pmh, char *cmd, char *arg) { char buf[CP_LINEMAX]; int count, len, n; pm_err_t err = PM_ESUCCESS; snprintf(buf, sizeof(buf), cmd, arg); snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), CP_EOL); count = 0; len = strlen(buf); while (count < len) { n = write(pmh->pmh_fd, buf + count, len - count); if (n < 0) { err = PM_ERRNOVALID; break; } count += n; } return err; } /* Send command [cmd] with argument [arg] to server handle [pmh]. * If [respp] is non-NULL, return list of response lines which * the caller must free. */ static pm_err_t _server_command(pm_handle_t pmh, char *cmd, char *arg, struct list_struct **respp) { pm_err_t err; if ((err = _server_send_command(pmh, cmd, arg)) != PM_ESUCCESS) return err; if ((err = _server_recv_response(pmh, respp)) != PM_ESUCCESS) return err; return PM_ESUCCESS; } pm_err_t pm_connect(char *server, void *arg, pm_handle_t *pmhp, int flags) { pm_handle_t pmh = NULL; pm_err_t err; if (pmhp == NULL) return PM_EBADARG; if ((pmh = (pm_handle_t)malloc(sizeof(struct pm_handle_struct))) == NULL) return PM_ENOMEM; if ((err = _connect_to_server_tcp(pmh, server, (flags & PM_CONN_INET6) ? PF_INET6 : PF_UNSPEC)) != PM_ESUCCESS) { (void)close(pmh->pmh_fd); free(pmh); return err; } if ((err = _server_recv_response(pmh, NULL)) != PM_ESUCCESS) { (void)close(pmh->pmh_fd); free(pmh); return err; } if ((err = _server_command(pmh, CP_EXPRANGE, NULL, NULL)) != PM_ESUCCESS) { (void)close(pmh->pmh_fd); free(pmh); return err; } if (err == PM_ESUCCESS) *pmhp = pmh; else free(pmh); return err; } static pm_err_t _node_iterator_create(pm_node_iterator_t *pmip) { pm_node_iterator_t pmi; if (!(pmi = malloc(sizeof(struct pm_node_iterator_struct)))) return PM_ENOMEM; pmi->pmi_pos = pmi->pmi_nodes = NULL; *pmip = pmi; return PM_ESUCCESS; } void pm_node_iterator_destroy(pm_node_iterator_t pmi) { _list_free(&pmi->pmi_nodes); pmi->pmi_pos = NULL; free(pmi); } pm_err_t pm_node_iterator_create(pm_handle_t pmh, pm_node_iterator_t *pmip) { pm_node_iterator_t pmi; struct list_struct *lp, *resp; char *cpy, node[CP_LINEMAX]; pm_err_t err; if (pmh == NULL) return PM_EBADHAND; if ((err = _node_iterator_create(&pmi)) != PM_ESUCCESS) return err; if ((err = _server_command(pmh, CP_NODES, NULL, &resp)) != PM_ESUCCESS) { pm_node_iterator_destroy(pmi); return err; } for (lp = resp; lp != NULL; lp = lp->next) { if (sscanf(lp->data, CP_INFO_XNODES, node) == 1) { if (!(cpy = strdup(node))) { err = PM_ENOMEM; break; } err = _list_add(&pmi->pmi_nodes, cpy, (list_free_t)free); if (err != PM_ESUCCESS) break; } } if (err == PM_ESUCCESS && pmip != NULL) { pm_node_iterator_reset(pmi); *pmip = pmi; } else pm_node_iterator_destroy(pmi); _list_free(&resp); return err; } char * pm_node_next(pm_node_iterator_t pmi) { struct list_struct *cur = pmi->pmi_pos; if (!cur) return NULL; pmi->pmi_pos = pmi->pmi_pos->next; return cur->data; } void pm_node_iterator_reset(pm_node_iterator_t pmi) { pmi->pmi_pos = pmi->pmi_nodes; } /* Disconnect from server handle [pmh] and free the handle. */ void pm_disconnect(pm_handle_t pmh) { if (pmh != NULL) { (void)_server_command(pmh, CP_QUIT, NULL, NULL); /* PM_ESERVEREOF */ (void)close(pmh->pmh_fd); free(pmh); } } /* Query server [pmh] for the power status of [node], and store it * in [statep]. */ pm_err_t pm_node_status(pm_handle_t pmh, char *node, pm_node_state_t *statep) { char offstr[CP_LINEMAX], onstr[CP_LINEMAX]; pm_err_t err; struct list_struct *resp; pm_node_state_t state; if (pmh == NULL) return PM_EBADHAND; if ((err = _server_command(pmh, CP_STATUS, node, &resp)) != PM_ESUCCESS) return err; snprintf(offstr, sizeof(offstr), CP_INFO_XSTATUS, node, "off"); snprintf(onstr, sizeof(onstr), CP_INFO_XSTATUS, node, "on"); if (_list_search(resp, offstr)) state = PM_OFF; else if (_list_search(resp, onstr)) state = PM_ON; else state = PM_UNKNOWN; _list_free(&resp); if (statep) *statep = state; return PM_ESUCCESS; } /* Tell server [pmh] to turn [node] on. */ pm_err_t pm_node_on(pm_handle_t pmh, char *node) { if (pmh == NULL) return PM_EBADHAND; return _server_command(pmh, CP_ON, node, NULL); } /* Tell server [pmh] to turn [node] off. */ pm_err_t pm_node_off(pm_handle_t pmh, char *node) { if (pmh == NULL) return PM_EBADHAND; return _server_command(pmh, CP_OFF, node, NULL); } /* Tell server [pmh] to cycle [node]. */ pm_err_t pm_node_cycle(pm_handle_t pmh, char *node) { if (pmh == NULL) return PM_EBADHAND; return _server_command(pmh, CP_CYCLE, node, NULL); } /* Convert error code to human readable string. */ char * pm_strerror(pm_err_t err, char *str, int len) { switch (err) { case PM_ESUCCESS: strncpy(str, "success", len); break; case PM_ERRNOVALID: strncpy(str, strerror(errno), len); break; case PM_ENOADDR: strncpy(str, "failed to get address info for server", len); break; case PM_ECONNECT: strncpy(str, "connect failed", len); break; case PM_ENOMEM: strncpy(str, "out of memory", len); break; case PM_EBADHAND: strncpy(str, "bad server handle", len); break; case PM_EBADARG: strncpy(str, "bad argument", len); break; case PM_ESERVEREOF: strncpy(str, "received unexpected EOF from server", len); break; case PM_ESERVERPARSE: strncpy(str, "unexpected response from server", len); break; case PM_EUNKNOWN: strncpy(str, "server: unknown command", len); break; case PM_EPARSE: strncpy(str, "server: parse error", len); break; case PM_ETOOLONG: strncpy(str, "server: command too long", len); break; case PM_EINTERNAL: strncpy(str, "server: internal error", len); break; case PM_EHOSTLIST: strncpy(str, "server: hostlist error", len); break; case PM_EINPROGRESS: strncpy(str, "server: command in progress", len); break; case PM_ENOSUCHNODES: strncpy(str, "server: no such nodes", len); break; case PM_ECOMMAND: strncpy(str, "server: command completed with errors", len); break; case PM_EQUERY: strncpy(str, "server: query completed with errors", len); break; case PM_EUNIMPL: strncpy(str, "server: not implemented by device", len); break; } return str; } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/libpowerman.h000066400000000000000000000055301467035776500205070ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef LIBPOWERMAN_H #define LIBPOWERMAN_H #ifdef __cplusplus extern "C" { #endif typedef struct pm_handle_struct *pm_handle_t; typedef struct pm_node_iterator_struct *pm_node_iterator_t; typedef enum { PM_UNKNOWN = 0, PM_OFF = 1, PM_ON = 2, } pm_node_state_t; typedef enum { PM_ESUCCESS = 0, /* success */ PM_ERRNOVALID = 1, /* system call failed, see system errno */ PM_ENOADDR = 2, /* failed to get address info for server */ PM_ECONNECT = 3, /* connect failed */ PM_ENOMEM = 4, /* out of memory */ PM_EBADHAND = 5, /* bad server handle */ PM_EBADARG = 6, /* bad argument */ PM_ESERVEREOF = 7, /* received unexpected EOF from server */ PM_ESERVERPARSE = 8, /* unexpected response from server */ PM_EUNKNOWN = 201, /* server: unknown command (201) */ PM_EPARSE = 202, /* server: parse error (202) */ PM_ETOOLONG = 203, /* server: command too long (203) */ PM_EINTERNAL = 204, /* server: internal error (204) */ PM_EHOSTLIST = 205, /* server: hostlist error (205) */ PM_EINPROGRESS = 208, /* server: command in progress (208) */ PM_ENOSUCHNODES = 209, /* server: no such nodes (209) */ PM_ECOMMAND = 210, /* server: command completed with errors (210) */ PM_EQUERY = 211, /* server: query completed with errors (211) */ PM_EUNIMPL = 213, /* server: not implemented by device (213) */ } pm_err_t; /* flags for pm_connect() */ #define PM_CONN_INET6 1 /* connect using IPv6 only */ #define PM_CONN_COPROC 2 /* unimplemented */ pm_err_t pm_connect(char *server, void *arg, pm_handle_t *pmhp, int flags); void pm_disconnect(pm_handle_t pmh); pm_err_t pm_node_status(pm_handle_t pmh, char *node, pm_node_state_t *statep); pm_err_t pm_node_on(pm_handle_t pmh, char *node); pm_err_t pm_node_off(pm_handle_t pmh, char *node); pm_err_t pm_node_cycle(pm_handle_t pmh, char *node); pm_err_t pm_node_iterator_create(pm_handle_t pmh, pm_node_iterator_t *pmip); char * pm_node_next(pm_node_iterator_t pmi); void pm_node_iterator_reset(pm_node_iterator_t pmi); void pm_node_iterator_destroy(pm_node_iterator_t pmi); char * pm_strerror(pm_err_t err, char *str, int len); #define PM_DFLT_PORT "10101" #define PM_DFLT_HOST "localhost" #ifdef __cplusplus } #endif #endif /* PM_POWERMAN_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/parse_lex.l000066400000000000000000000140201467035776500201500ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ %x lex_incl lex_str %{ #if HAVE_CONFIG_H #include "config.h" #endif /* N.B. must define YYSTYPE before including parse_tab.h or type will be int. */ #define YYSTYPE char * extern YYSTYPE yylval; #include #include #include #include "hostlist.h" #include "parse_tab.h" #include "list.h" #include "xmalloc.h" #include "error.h" #include "parse_util.h" extern void yyerror(); #define YY_NO_INPUT /* silence compiler warnings about unused input() */ #define MAX_INCLUDE_DEPTH 10 static YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; static int linenum[MAX_INCLUDE_DEPTH]; static char *filename[MAX_INCLUDE_DEPTH]; static int include_stack_ptr = 0; static char string_buf[8192]; static char *string_buf_ptr; static List line_ptrs; %} /* Lex Options */ %option nounput %% %{ /* yyin gets initialized in parse.y */ %} #[^\n]*\n { linenum[include_stack_ptr]++; } [ \t\r]+ { /* Eat up white space */ } [\n] { linenum[include_stack_ptr]++; } ([0-9]+)|([0-9]+"."[0-9]*)|("."[0-9]+) { yylval = yytext; return TOK_NUMERIC_VAL; } \$ { return TOK_MATCHPOS; } \" { string_buf_ptr = string_buf; BEGIN(lex_str); } { \" { BEGIN(INITIAL); *string_buf_ptr = '\0'; yylval = xstrdup (string_buf); list_append(line_ptrs, yylval); return TOK_STRING_VAL; } "\\a" { *string_buf_ptr++ = '\a'; } "\\b" { *string_buf_ptr++ = '\b'; } "\\e" { *string_buf_ptr++ = '\e'; } "\\f" { *string_buf_ptr++ = '\f'; } "\\n" { *string_buf_ptr++ = '\n'; } "\\r" { *string_buf_ptr++ = '\r'; } "\\t" { *string_buf_ptr++ = '\t'; } "\\v" { *string_buf_ptr++ = '\v'; } "\n" { yyerror(); } \\[0-9][0-9][0-9] { *string_buf_ptr++ = strtol(&yytext[1], NULL, 8); } \\(.|\n) { *string_buf_ptr++ = yytext[1]; } [^\\\n\"]+ { char *yptr = yytext; while ( *yptr ) *string_buf_ptr++ = *yptr++; } } listen return TOK_LISTEN; tcpwrappers return TOK_TCP_WRAPPERS; plug_log_level return TOK_PLUG_LOG_LEVEL; timeout return TOK_DEV_TIMEOUT; pingperiod return TOK_PING_PERIOD; specification return TOK_SPEC; expect return TOK_EXPECT; setplugstate return TOK_SETPLUGSTATE; setresult return TOK_SETRESULT; foreachnode return TOK_FOREACHNODE; foreachplug return TOK_FOREACHPLUG; ifoff return TOK_IFOFF; ifon return TOK_IFON; send return TOK_SEND; delay return TOK_DELAY; login return TOK_LOGIN; logout return TOK_LOGOUT; status return TOK_STATUS; status_all return TOK_STATUS_ALL; on return TOK_ON; on_ranged return TOK_ON_RANGED; on_all return TOK_ON_ALL; off return TOK_OFF; off_ranged return TOK_OFF_RANGED; off_all return TOK_OFF_ALL; cycle return TOK_CYCLE; cycle_ranged return TOK_CYCLE_RANGED; cycle_all return TOK_CYCLE_ALL; reset return TOK_RESET; reset_ranged return TOK_RESET_RANGED; reset_all return TOK_RESET_ALL; ping return TOK_PING; status_temp return TOK_STATUS_TEMP; status_temp_all return TOK_STATUS_TEMP_ALL; status_beacon return TOK_STATUS_BEACON; status_beacon_all return TOK_STATUS_BEACON_ALL; beacon_on return TOK_BEACON_ON; beacon_on_ranged return TOK_BEACON_ON_RANGED; beacon_off return TOK_BEACON_OFF; beacon_off_ranged return TOK_BEACON_OFF_RANGED; device return TOK_DEVICE; plug[ \t]+name return TOK_PLUG_NAME; node return TOK_NODE; yes return TOK_YES; no return TOK_NO; success return TOK_SUCCESS; \{ return TOK_BEGIN; \} return TOK_END; = return TOK_EQUALS; script return TOK_SCRIPT; alias return TOK_ALIAS; include BEGIN(lex_incl); [ \t]* { /* eat white space */ } [\n] { linenum[include_stack_ptr]++; } [^ \t\n]+ { /* got include file name */ int len; len = strlen(yytext); yytext[len - 1] = '\0'; if ( include_stack_ptr >= MAX_INCLUDE_DEPTH - 1 ) err_exit(false, "Includes nested too deeply" ); include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER; linenum[include_stack_ptr] = 1; yyin = fopen( yytext + 1, "r" ); if ( yyin == NULL ) err_exit(true, "%s", yytext + 1); filename[include_stack_ptr] = xstrdup(yytext + 1); yy_switch_to_buffer( yy_create_buffer( yyin, YY_BUF_SIZE ) ); BEGIN(INITIAL); } <> { if (include_stack_ptr == 0) { yyterminate(); } else { /* do I need an fclose(yyin); here? */ yy_delete_buffer( YY_CURRENT_BUFFER ); yy_switch_to_buffer( include_stack[--include_stack_ptr] ); } } . { return TOK_UNRECOGNIZED; } %% /* provide yywrap() to avoid need to link to -lfl */ int yywrap() { return 1; } int scanner_line(void) { return linenum[include_stack_ptr]; } void scanner_line_destroy(char *ptr) { xfree(ptr); } char * scanner_file(void) { return filename[include_stack_ptr]; } void scanner_init(char *filename0) { int i; for (i = 0; i < MAX_INCLUDE_DEPTH; i++) { linenum[i] = 1; filename[i] = NULL; } filename[0] = xstrdup(filename0); line_ptrs = list_create((ListDelF)scanner_line_destroy); } void scanner_fini(void) { int i; for (i = 0; i < MAX_INCLUDE_DEPTH; i++) { if (filename[i] != NULL) xfree(filename[i]); } list_destroy(line_ptrs); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/parse_tab.y000066400000000000000000000621411467035776500201520ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ %{ #if HAVE_CONFIG_H #include "config.h" #endif #define YYSTYPE char * /* The generic type returned by all parse matches */ #undef YYDEBUG /* no debug code please */ #include #include #include #include #include /* for HUGE_VAL and trunc */ #include #include #include #include #include #include #include #include "list.h" #include "cbuf.h" #include "hostlist.h" #include "xmalloc.h" #include "xpoll.h" #include "xregex.h" #include "pluglist.h" #include "arglist.h" #include "device_private.h" #include "device_serial.h" #include "device_pipe.h" #include "device_tcp.h" #include "parse_util.h" #include "error.h" /* * A PreScript is a list of PreStmts. */ typedef struct { StmtType type; /* delay/expect/send */ char *str; /* expect string, send fmt, setplugstate plug */ struct timeval tv; /* delay value */ int mp1; /* setplugstate/result plug match position */ int mp2; /* setplugstate/result state/result match position */ List prestmts; /* subblock */ List state_interps; /* interpretations for setplugstate */ List result_interps; /* interpretations for setresult */ } PreStmt; typedef List PreScript; /* * Unprocessed Protocol (used during parsing). * This data will be copied for each instantiation of a device. */ typedef struct { char *name; /* specification name, e.g. "icebox" */ struct timeval timeout; /* timeout for this device */ struct timeval ping_period; /* ping period for this device 0.0 = none */ List plugs; /* list of plug names (e.g. "1" thru "10") */ PreScript prescripts[NUM_SCRIPTS]; /* array of PreScripts */ } Spec; /* script may be NULL if undefined */ /* powerman.conf */ static void makeNode(char *nodestr, char *devstr, char *plugstr); static void makeAlias(char *namestr, char *hostsstr); static Stmt *makeStmt(PreStmt *p); static void destroyStmt(Stmt *stmt); static void makeDevice(char *devstr, char *specstr, char *hoststr, char *portstr); /* device config */ static PreStmt *makePreStmt(StmtType type, char *str, char *tvstr, char *mp1str, char *mp2str, List prestmts, List plugstate_interps, List result_interps); static void destroyPreStmt(PreStmt *p); static Spec *makeSpec(char *name); static Spec *findSpec(char *name); static int matchSpec(Spec * spec, void *key); static void destroySpec(Spec * spec); static void makeScript(int com, List stmts); static void destroyStateInterp(StateInterp *i); static StateInterp *makeStateInterp(InterpState state, char *str); static List copyStateInterpList(List ilist); static void destroyResultInterp(ResultInterp *i); static ResultInterp *makeResultInterp(InterpResult result, char *str); static List copyResultInterpList(List ilist); /* utility functions */ static void _errormsg(char *msg); static void _warnmsg(char *msg); static long _strtolong(char *str); static double _strtodouble(char *str); static void _doubletotv(struct timeval *tv, double val); extern int yylex(); void yyerror(); static List device_specs = NULL; /* list of Spec's */ static Spec current_spec; /* Holds a Spec as it is built */ %} /* script names */ %token TOK_LOGIN TOK_LOGOUT TOK_STATUS TOK_STATUS_ALL %token TOK_STATUS_TEMP TOK_STATUS_TEMP_ALL %token TOK_STATUS_BEACON TOK_STATUS_BEACON_ALL %token TOK_BEACON_ON TOK_BEACON_ON_RANGED TOK_BEACON_OFF TOK_BEACON_OFF_RANGED %token TOK_ON TOK_ON_RANGED TOK_ON_ALL TOK_OFF TOK_OFF_RANGED TOK_OFF_ALL %token TOK_CYCLE TOK_CYCLE_RANGED TOK_CYCLE_ALL %token TOK_RESET TOK_RESET_RANGED TOK_RESET_ALL TOK_PING TOK_SPEC /* script statements */ %token TOK_EXPECT TOK_SETPLUGSTATE TOK_SETRESULT TOK_SEND TOK_DELAY %token TOK_FOREACHPLUG TOK_FOREACHNODE TOK_IFOFF TOK_IFON /* other device configuration stuff */ %token TOK_OFF_STRING TOK_ON_STRING %token TOK_MAX_PLUG_COUNT TOK_TIMEOUT TOK_DEV_TIMEOUT TOK_PING_PERIOD %token TOK_PLUG_NAME TOK_SCRIPT /* powerman.conf stuff */ %token TOK_DEVICE TOK_NODE TOK_ALIAS TOK_TCP_WRAPPERS TOK_LISTEN TOK_PLUG_LOG_LEVEL /* general */ %token TOK_MATCHPOS TOK_STRING_VAL TOK_NUMERIC_VAL TOK_YES TOK_NO %token TOK_BEGIN TOK_END TOK_UNRECOGNIZED TOK_EQUALS %token TOK_SUCCESS %% /* Grammar Rules for the powerman.conf config file */ configuration_file : config_list ; /**************************************************************/ /* config_list */ /**************************************************************/ config_list : config_list config_item | config_item | ; config_item : listen | TCP_wrappers | plug_log_level | device | node | alias | spec ; TCP_wrappers : TOK_TCP_WRAPPERS { _warnmsg("'tcpwrappers' without yes|no"); conf_set_use_tcp_wrappers(true); } | TOK_TCP_WRAPPERS TOK_YES { conf_set_use_tcp_wrappers(true); } | TOK_TCP_WRAPPERS TOK_NO { conf_set_use_tcp_wrappers(false); } ; plug_log_level : TOK_PLUG_LOG_LEVEL TOK_STRING_VAL { conf_set_plug_log_level($2); } ; listen : TOK_LISTEN TOK_STRING_VAL { conf_add_listen($2); } ; device : TOK_DEVICE TOK_STRING_VAL TOK_STRING_VAL TOK_STRING_VAL TOK_STRING_VAL { makeDevice($2, $3, $4, $5); } | TOK_DEVICE TOK_STRING_VAL TOK_STRING_VAL TOK_STRING_VAL { makeDevice($2, $3, $4, NULL); } ; node : TOK_NODE TOK_STRING_VAL TOK_STRING_VAL TOK_STRING_VAL { makeNode($2, $3, $4); } | TOK_NODE TOK_STRING_VAL TOK_STRING_VAL { makeNode($2, $3, NULL); } ; alias : TOK_ALIAS TOK_STRING_VAL TOK_STRING_VAL { makeAlias($2, $3); } ; /**************************************************************/ /* specifications */ /**************************************************************/ spec : TOK_SPEC TOK_STRING_VAL TOK_BEGIN spec_item_list TOK_END { makeSpec($2); } ; spec_item_list : spec_item_list spec_item | spec_item ; spec_item : spec_timeout | spec_ping_period | spec_plug_list | spec_script_list ; spec_timeout : TOK_DEV_TIMEOUT TOK_NUMERIC_VAL { _doubletotv(¤t_spec.timeout, _strtodouble($2)); } ; spec_ping_period: TOK_PING_PERIOD TOK_NUMERIC_VAL { _doubletotv(¤t_spec.ping_period, _strtodouble($2)); } ; string_list : string_list TOK_STRING_VAL { list_append((List)$1, xstrdup($2)); $$ = $1; } | TOK_STRING_VAL { $$ = (char *)list_create((ListDelF)xfree); list_append((List)$$, xstrdup($1)); } ; spec_plug_list : TOK_PLUG_NAME TOK_BEGIN string_list TOK_END { if (current_spec.plugs != NULL) _errormsg("duplicate plug list"); current_spec.plugs = (List)$3; } ; spec_script_list : spec_script_list spec_script | spec_script ; spec_script : TOK_SCRIPT TOK_LOGIN stmt_block { makeScript(PM_LOG_IN, (List)$3); } | TOK_SCRIPT TOK_LOGOUT stmt_block { makeScript(PM_LOG_OUT, (List)$3); } | TOK_SCRIPT TOK_STATUS stmt_block { makeScript(PM_STATUS_PLUGS, (List)$3); } | TOK_SCRIPT TOK_STATUS_ALL stmt_block { makeScript(PM_STATUS_PLUGS_ALL, (List)$3); } | TOK_SCRIPT TOK_STATUS_TEMP stmt_block { makeScript(PM_STATUS_TEMP, (List)$3); } | TOK_SCRIPT TOK_STATUS_TEMP_ALL stmt_block { makeScript(PM_STATUS_TEMP_ALL, (List)$3); } | TOK_SCRIPT TOK_STATUS_BEACON stmt_block { makeScript(PM_STATUS_BEACON, (List)$3); } | TOK_SCRIPT TOK_STATUS_BEACON_ALL stmt_block { makeScript(PM_STATUS_BEACON_ALL, (List)$3); } | TOK_SCRIPT TOK_BEACON_ON stmt_block { makeScript(PM_BEACON_ON, (List)$3); } | TOK_SCRIPT TOK_BEACON_ON_RANGED stmt_block { makeScript(PM_BEACON_ON_RANGED, (List)$3); } | TOK_SCRIPT TOK_BEACON_OFF stmt_block { makeScript(PM_BEACON_OFF, (List)$3); } | TOK_SCRIPT TOK_BEACON_OFF_RANGED stmt_block { makeScript(PM_BEACON_OFF_RANGED, (List)$3); } | TOK_SCRIPT TOK_ON stmt_block { makeScript(PM_POWER_ON, (List)$3); } | TOK_SCRIPT TOK_ON_RANGED stmt_block { makeScript(PM_POWER_ON_RANGED, (List)$3); } | TOK_SCRIPT TOK_ON_ALL stmt_block { makeScript(PM_POWER_ON_ALL, (List)$3); } | TOK_SCRIPT TOK_OFF stmt_block { makeScript(PM_POWER_OFF, (List)$3); } | TOK_SCRIPT TOK_OFF_RANGED stmt_block { makeScript(PM_POWER_OFF_RANGED, (List)$3); } | TOK_SCRIPT TOK_OFF_ALL stmt_block { makeScript(PM_POWER_OFF_ALL, (List)$3); } | TOK_SCRIPT TOK_CYCLE stmt_block { makeScript(PM_POWER_CYCLE, (List)$3); } | TOK_SCRIPT TOK_CYCLE_RANGED stmt_block { makeScript(PM_POWER_CYCLE_RANGED, (List)$3); } | TOK_SCRIPT TOK_CYCLE_ALL stmt_block { makeScript(PM_POWER_CYCLE_ALL, (List)$3); } | TOK_SCRIPT TOK_RESET stmt_block { makeScript(PM_RESET, (List)$3); } | TOK_SCRIPT TOK_RESET_RANGED stmt_block { makeScript(PM_RESET_RANGED, (List)$3); } | TOK_SCRIPT TOK_RESET_ALL stmt_block { makeScript(PM_RESET_ALL, (List)$3); } | TOK_SCRIPT TOK_PING stmt_block { makeScript(PM_PING, (List)$3); } ; stmt_block : TOK_BEGIN stmt_list TOK_END { $$ = $2; } ; stmt_list : stmt_list stmt { list_append((List)$1, $2); $$ = $1; } | stmt { $$ = (char *)list_create((ListDelF)destroyPreStmt); list_append((List)$$, $1); } ; stmt : TOK_EXPECT TOK_STRING_VAL { $$ = (char *)makePreStmt(STMT_EXPECT, $2, NULL, NULL, NULL, NULL, NULL, NULL); } | TOK_SEND TOK_STRING_VAL { $$ = (char *)makePreStmt(STMT_SEND, $2, NULL, NULL, NULL, NULL, NULL, NULL); } | TOK_DELAY TOK_NUMERIC_VAL { $$ = (char *)makePreStmt(STMT_DELAY, NULL, $2, NULL, NULL, NULL, NULL, NULL); } | TOK_SETPLUGSTATE TOK_STRING_VAL regmatch { $$ = (char *)makePreStmt(STMT_SETPLUGSTATE, $2, NULL, NULL, $3, NULL, NULL, NULL); } | TOK_SETPLUGSTATE TOK_STRING_VAL regmatch state_interp_list { $$ = (char *)makePreStmt(STMT_SETPLUGSTATE, $2, NULL, NULL, $3, NULL, (List)$4, NULL); } | TOK_SETPLUGSTATE regmatch regmatch { $$ = (char *)makePreStmt(STMT_SETPLUGSTATE, NULL, NULL, $2, $3, NULL, NULL, NULL); } | TOK_SETPLUGSTATE regmatch regmatch state_interp_list { $$ = (char *)makePreStmt(STMT_SETPLUGSTATE, NULL, NULL, $2, $3, NULL, (List)$4, NULL); } | TOK_SETPLUGSTATE regmatch { $$ = (char *)makePreStmt(STMT_SETPLUGSTATE, NULL, NULL, NULL, $2, NULL, NULL, NULL); } | TOK_SETPLUGSTATE regmatch state_interp_list { $$ = (char *)makePreStmt(STMT_SETPLUGSTATE, NULL, NULL, NULL,$2,NULL, (List)$3, NULL); } | TOK_SETRESULT regmatch regmatch result_interp_list { $$ = (char *)makePreStmt(STMT_SETRESULT, NULL, NULL, $2, $3, NULL, NULL, (List)$4); } | TOK_FOREACHNODE stmt_block { $$ = (char *)makePreStmt(STMT_FOREACHNODE, NULL, NULL, NULL, NULL, (List)$2, NULL, NULL); } | TOK_FOREACHPLUG stmt_block { $$ = (char *)makePreStmt(STMT_FOREACHPLUG, NULL, NULL, NULL, NULL, (List)$2, NULL, NULL); } | TOK_IFOFF stmt_block { $$ = (char *)makePreStmt(STMT_IFOFF, NULL, NULL, NULL, NULL, (List)$2, NULL, NULL); } | TOK_IFON stmt_block { $$ = (char *)makePreStmt(STMT_IFON, NULL, NULL, NULL, NULL, (List)$2, NULL, NULL); } ; state_interp_list : state_interp_list state_interp { list_append((List)$1, $2); $$ = $1; } | state_interp { $$ = (char *)list_create((ListDelF)destroyStateInterp); list_append((List)$$, $1); } ; state_interp : TOK_ON TOK_EQUALS TOK_STRING_VAL { $$ = (char *)makeStateInterp(ST_ON, $3); } | TOK_OFF TOK_EQUALS TOK_STRING_VAL { $$ = (char *)makeStateInterp(ST_OFF, $3); } ; result_interp_list : result_interp_list result_interp { list_append((List)$1, $2); $$ = $1; } | result_interp { $$ = (char *)list_create((ListDelF)destroyResultInterp); list_append((List)$$, $1); } ; result_interp : TOK_SUCCESS TOK_EQUALS TOK_STRING_VAL { $$ = (char *)makeResultInterp(RT_SUCCESS, $3); } ; regmatch : TOK_MATCHPOS TOK_NUMERIC_VAL { $$ = $2; } ; %% void scanner_init(char *filename); void scanner_fini(void); int scanner_line(void); char *scanner_file(void); /* * Entry point into the yacc/lex parser. */ int parse_config_file (char *filename) { extern FILE *yyin; /* part of lexer */ scanner_init(filename); yyin = fopen(filename, "r"); if (!yyin) err_exit(true, "%s", filename); device_specs = list_create((ListDelF) destroySpec); yyparse(); fclose(yyin); scanner_fini(); list_destroy(device_specs); return 0; } /* makePreStmt(type, str, tv, mp1(plug), mp2(stat/node), prestmts, * state_interps, result_interps */ static PreStmt *makePreStmt(StmtType type, char *str, char *tvstr, char *mp1str, char *mp2str, List prestmts, List state_interps, List result_interps) { PreStmt *new; new = (PreStmt *) xmalloc(sizeof(PreStmt)); new->type = type; new->mp1 = mp1str ? _strtolong(mp1str) : -1; new->mp2 = mp2str ? _strtolong(mp2str) : -1; if (str) new->str = xstrdup(str); if (tvstr) _doubletotv(&new->tv, _strtodouble(tvstr)); new->prestmts = prestmts; new->state_interps = state_interps; new->result_interps = result_interps; return new; } static void destroyPreStmt(PreStmt *p) { if (p->str) xfree(p->str); p->str = NULL; if (p->prestmts) list_destroy(p->prestmts); p->prestmts = NULL; if (p->state_interps) list_destroy(p->state_interps); p->state_interps = NULL; if (p->result_interps) list_destroy(p->result_interps); p->result_interps = NULL; xfree(p); } static Spec *_copy_current_spec(void) { Spec *new = (Spec *) xmalloc(sizeof(Spec)); *new = current_spec; memset (¤t_spec, 0, sizeof (current_spec)); return new; } static Spec *makeSpec(char *name) { Spec *spec; current_spec.name = xstrdup(name); /* FIXME: check for manditory scripts here? what are they? */ spec = _copy_current_spec(); assert(device_specs != NULL); list_append(device_specs, spec); return spec; } static void destroySpec(Spec * spec) { int i; if (spec->name) xfree(spec->name); if (spec->plugs) list_destroy(spec->plugs); for (i = 0; i < NUM_SCRIPTS; i++) if (spec->prescripts[i]) list_destroy(spec->prescripts[i]); xfree(spec); } static int matchSpec(Spec * spec, void *key) { return (strcmp(spec->name, (char *) key) == 0); } static Spec *findSpec(char *name) { return list_find_first(device_specs, (ListFindF) matchSpec, name); } static void makeScript(int com, List stmts) { if (current_spec.prescripts[com] != NULL) _errormsg("duplicate script"); current_spec.prescripts[com] = stmts; } static StateInterp *makeStateInterp(InterpState state, char *str) { StateInterp *new = (StateInterp *)xmalloc(sizeof(StateInterp)); new->str = xstrdup(str); new->re = xregex_create(); new->state = state; return new; } static void destroyStateInterp(StateInterp *i) { xfree(i->str); xregex_destroy(i->re); xfree(i); } static List copyStateInterpList(List il) { ListIterator itr; StateInterp *ip, *icpy; List new = list_create((ListDelF) destroyStateInterp); if (il != NULL) { itr = list_iterator_create(il); while((ip = list_next(itr))) { icpy = makeStateInterp(ip->state, ip->str); xregex_compile(icpy->re, icpy->str, false); list_append(new, icpy); } list_iterator_destroy(itr); } return new; } static ResultInterp *makeResultInterp(InterpResult result, char *str) { ResultInterp *new = (ResultInterp *)xmalloc(sizeof(ResultInterp)); new->str = xstrdup(str); new->re = xregex_create(); new->result = result; return new; } static void destroyResultInterp(ResultInterp *i) { xfree(i->str); xregex_destroy(i->re); xfree(i); } static List copyResultInterpList(List il) { ListIterator itr; ResultInterp *ip, *icpy; List new = list_create((ListDelF) destroyResultInterp); if (il != NULL) { itr = list_iterator_create(il); while((ip = list_next(itr))) { icpy = makeResultInterp(ip->result, ip->str); xregex_compile(icpy->re, icpy->str, false); list_append(new, icpy); } list_iterator_destroy(itr); } return new; } /** ** Powerman.conf stuff. **/ static void destroyStmt(Stmt *stmt) { assert(stmt != NULL); switch (stmt->type) { case STMT_SEND: xfree(stmt->u.send.fmt); break; case STMT_EXPECT: xregex_destroy(stmt->u.expect.exp); break; case STMT_DELAY: break; case STMT_SETPLUGSTATE: list_destroy(stmt->u.setplugstate.interps); xfree (stmt->u.setplugstate.plug_name); break; case STMT_SETRESULT: list_destroy(stmt->u.setresult.interps); break; case STMT_FOREACHNODE: case STMT_FOREACHPLUG: list_destroy(stmt->u.foreach.stmts); break; case STMT_IFON: case STMT_IFOFF: list_destroy(stmt->u.ifonoff.stmts); break; default: break; } xfree(stmt); } static Stmt *makeStmt(PreStmt *p) { Stmt *stmt; PreStmt *subp; ListIterator itr; stmt = (Stmt *) xmalloc(sizeof(Stmt)); stmt->type = p->type; switch (p->type) { case STMT_SEND: stmt->u.send.fmt = xstrdup(p->str); break; case STMT_EXPECT: stmt->u.expect.exp = xregex_create(); xregex_compile(stmt->u.expect.exp, p->str, true); break; case STMT_SETPLUGSTATE: stmt->u.setplugstate.stat_mp = p->mp2; if (p->str) stmt->u.setplugstate.plug_name = xstrdup(p->str); else stmt->u.setplugstate.plug_mp = p->mp1; stmt->u.setplugstate.interps = copyStateInterpList(p->state_interps); break; case STMT_SETRESULT: stmt->u.setresult.stat_mp = p->mp2; stmt->u.setresult.plug_mp = p->mp1; stmt->u.setresult.interps = copyResultInterpList(p->result_interps); break; case STMT_DELAY: stmt->u.delay.tv = p->tv; break; case STMT_FOREACHNODE: case STMT_FOREACHPLUG: stmt->u.foreach.stmts = list_create((ListDelF) destroyStmt); itr = list_iterator_create(p->prestmts); while((subp = list_next(itr))) { list_append(stmt->u.foreach.stmts, makeStmt(subp)); } list_iterator_destroy(itr); break; case STMT_IFON: case STMT_IFOFF: stmt->u.ifonoff.stmts = list_create((ListDelF) destroyStmt); itr = list_iterator_create(p->prestmts); while((subp = list_next(itr))) { list_append(stmt->u.ifonoff.stmts, makeStmt(subp)); } list_iterator_destroy(itr); break; default: break; } return stmt; } static void _parse_hoststr(Device *dev, char *hoststr, char *flagstr) { /* pipe device, e.g. "conman -j baytech0 |&" */ if (strstr(hoststr, "|&") != NULL) { dev->data = pipe_create(hoststr, flagstr); dev->destroy = pipe_destroy; dev->connect = pipe_connect; dev->disconnect = pipe_disconnect; dev->finish_connect = NULL; dev->preprocess = NULL; /* serial device, e.g. "/dev/ttyS0" */ } else if (hoststr[0] == '/') { struct stat sb; if (stat(hoststr, &sb) == -1 || (!(sb.st_mode & S_IFCHR))) _errormsg("serial device not found or not a char special file"); dev->data = serial_create(hoststr, flagstr); dev->destroy = serial_destroy; dev->connect = serial_connect; dev->disconnect = serial_disconnect; dev->finish_connect = NULL; dev->preprocess = NULL; /* tcp device, e.g. "cyclades0:2001" */ } else { char *port = strchr(hoststr, ':'); int n; if (port) { /* host='host:port', flags=NULL */ *port++ = '\0'; } else _errormsg("hostname is missing :port"); n = _strtolong(port); /* verify port number */ if (n < 1 || n > 65535) _errormsg("port number out of range"); dev->data = tcp_create(hoststr, port, flagstr); dev->destroy = tcp_destroy; dev->connect = tcp_connect; dev->disconnect = tcp_disconnect; dev->finish_connect = tcp_finish_connect; dev->preprocess = tcp_preprocess; } } static void makeDevice(char *devstr, char *specstr, char *hoststr, char *flagstr) { ListIterator itr; Device *dev; Spec *spec; int i; /* find that spec */ spec = findSpec(specstr); if ( spec == NULL ) _errormsg("device specification not found"); /* make the Device */ dev = dev_create(devstr); dev->specname = xstrdup(specstr); dev->timeout = spec->timeout; dev->ping_period = spec->ping_period; _parse_hoststr(dev, hoststr, flagstr); /* create plugs (spec->plugs may be NULL) */ dev->plugs = pluglist_create(spec->plugs); /* transfer remaining info from the spec to the device */ for (i = 0; i < NUM_SCRIPTS; i++) { PreStmt *p; if (spec->prescripts[i] == NULL) { dev->scripts[i] = NULL; continue; /* unimplemented script */ } dev->scripts[i] = list_create((ListDelF) destroyStmt); /* copy the list of statements in each script */ itr = list_iterator_create(spec->prescripts[i]); while((p = list_next(itr))) { list_append(dev->scripts[i], makeStmt(p)); } list_iterator_destroy(itr); } dev_add(dev); } static void makeAlias(char *namestr, char *hostsstr) { if (!conf_add_alias(namestr, hostsstr)) _errormsg("bad alias"); } static void makeNode(char *nodestr, char *devstr, char *plugstr) { Device *dev = dev_findbyname(devstr); if (dev == NULL) _errormsg("unknown device"); /* plugstr can be NULL - see comment in pluglist.h */ switch (pluglist_map(dev->plugs, nodestr, plugstr)) { case EPL_DUPNODE: _errormsg("duplicate node"); case EPL_UNKPLUG: _errormsg("unknown plug name"); case EPL_DUPPLUG: _errormsg("plug already assigned"); case EPL_NOPLUGS: _errormsg("more nodes than plugs"); case EPL_NONODES: _errormsg("more plugs than nodes"); default: break; } if (!conf_addnodes(nodestr)) _errormsg("duplicate node name"); } /** ** Utility functions **/ static double _strtodouble(char *str) { char *endptr; double val = strtod(str, &endptr); if (val == 0.0 && endptr == str) _errormsg("error parsing double value"); if ((val == HUGE_VAL || val == -HUGE_VAL) && errno == ERANGE) _errormsg("double value would cause overflow"); return val; } static long _strtolong(char *str) { char *endptr; long val = strtol(str, &endptr, 0); if (val == 0 && endptr == str) _errormsg("error parsing long integer value"); if ((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE) _errormsg("long integer value would cause under/overflow"); return val; } static void _doubletotv(struct timeval *tv, double val) { tv->tv_sec = (val * 10.0)/10; /* crude round-down without -lm */ tv->tv_usec = ((val - tv->tv_sec) * 1000000.0); } static void _errormsg(char *msg) { err_exit(false, "%s: %s::%d", msg, scanner_file(), scanner_line()); } static void _warnmsg(char *msg) { err(false, "warning: %s: %s::%d", msg, scanner_file(), scanner_line()); } void yyerror() { _errormsg("parse error"); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/parse_util.c000066400000000000000000000177671467035776500203510ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include /* * Define SYSLOG_NAMES to allow access to level names * needed for parsing in string_to_level(). */ #ifndef SYSLOG_NAMES #define SYSLOG_NAMES 1 #define UNDO_SYSLOG_NAMES 1 #endif #include #ifdef UNDO_SYSLOG_NAMES #undef SYSLOG_NAMES #undef UNDO_SYSLOG_NAMES #endif #include "list.h" #include "hostlist.h" #include "error.h" #include "parse_util.h" #include "xmalloc.h" #include "xpoll.h" #include "pluglist.h" #include "client.h" #include "powerman.h" typedef struct { char *name; hostlist_t hl; } alias_t; static bool conf_use_tcp_wrap = false; static int conf_plug_log_level = LOG_DEBUG; /* syslog level */ static List conf_listen = NULL; /* list of host:port strings */ static hostlist_t conf_nodes = NULL; static List conf_aliases = NULL; /* list of alias_t's */ static bool _validate_config(void); static void _alias_destroy(alias_t *a); extern int parse_config_file(char *filename); /* yacc/lex parser */ /* * initialize module * parse the named config file - on error, exit with a message to stderr */ void conf_init(char *filename) { struct stat stbuf; bool valid; conf_listen = list_create((ListDelF) xfree); conf_nodes = hostlist_create(NULL); conf_aliases = list_create((ListDelF) _alias_destroy); /* validate config file */ if (stat(filename, &stbuf) < 0) err_exit(true, "%s", filename); if ((stbuf.st_mode & S_IFMT) != S_IFREG) err_exit(false, "%s is not a regular file\n", filename); /* * Call yacc parser against config file. * The parser builds 'dev_devices' (devices.c) and 'conf_*' (here). */ parse_config_file(filename); valid = _validate_config(); if (!valid) exit(1); } /* finalize module */ void conf_fini(void) { if (conf_aliases != NULL) list_destroy(conf_aliases); if (conf_nodes != NULL) hostlist_destroy(conf_nodes); if (conf_listen != NULL) list_destroy(conf_listen); } /* * Check the config file and exit with error if any problems are found. */ static bool _validate_config(void) { ListIterator itr; bool valid = true; alias_t *a; /* make sure aliases do not point to bogus node names */ itr = list_iterator_create(conf_aliases); while ((a = list_next(itr)) != NULL) { hostlist_iterator_t hitr = hostlist_iterator_create(a->hl); char *host; if (hitr == NULL) err_exit(false, "hostlist_iterator_create failed"); while ((host = hostlist_next(hitr)) != NULL) { if (!conf_node_exists(host)) { err(false, "alias '%s' references nonexistent node '%s'", a->name, host); valid = false; free(host); break; } else free(host); } hostlist_iterator_destroy(hitr); } list_iterator_destroy(itr); /* make sure there is at least one node defined */ if (hostlist_is_empty(conf_nodes)) { err(false, "no nodes are defined"); valid = false; } /* if no listen ports, add the default */ if (list_count(conf_listen) == 0) { char *s = xmalloc(strlen(DFLT_HOSTNAME) + strlen(DFLT_PORT) + 2); sprintf(s, "%s:%s", DFLT_HOSTNAME, DFLT_PORT); list_append(conf_listen, s); } return valid; } /* * Node conf_nodes list. */ bool conf_node_exists(char *node) { int res; res = hostlist_find(conf_nodes, node); return (res == -1 ? false : true); } bool conf_addnodes(char *nodelist) { hostlist_t hl = hostlist_create(nodelist); hostlist_iterator_t itr = hostlist_iterator_create(hl); char *node; int res = true; while ((node = hostlist_next(itr))) { if (conf_node_exists(node)) { free(node); res = false; break; } else { hostlist_push(conf_nodes, node); free(node); } } hostlist_iterator_destroy(itr); hostlist_destroy(hl); return res; } hostlist_t conf_getnodes(void) { return conf_nodes; } /* * Accessor functions for misc. configurable values. */ bool conf_get_use_tcp_wrappers(void) { return conf_use_tcp_wrap; } void conf_set_use_tcp_wrappers(bool val) { #if ! HAVE_TCP_WRAPPERS if (val == true) err_exit(false, "powerman was not built with tcp_wrapper support"); #endif conf_use_tcp_wrap = val; } List conf_get_listen(void) { return conf_listen; } void conf_add_listen(char *hostport) { list_append(conf_listen, xstrdup(hostport)); } /* * Return the corresponding integer value if syslog prioritynames * contains a name identical to s. If no match can be found, return (-1) * and set errno to EINVAL. */ static int string_to_level(char *s) { int level = -1; CODE *record = prioritynames; if (!s || *s == '\0') return -1; while (record->c_val != -1) { if (strcmp(s, record->c_name) == 0) { level = record->c_val; break; } record++; } return level; } int conf_get_plug_log_level(void) { return conf_plug_log_level; } void conf_set_plug_log_level(char *level_string) { int level = string_to_level(level_string); if (level < 0) err_exit(false, "unable to recognize plug_log_level config value"); conf_plug_log_level = level; } /* * Manage a list of nodename aliases. */ static int _alias_match(alias_t *a, char *name) { return (strcmp(a->name, name) == 0); } /* Expand any aliases present in hostlist. * N.B. Aliases cannot contain other aliases. */ void conf_exp_aliases(hostlist_t hl) { hostlist_iterator_t itr = NULL; hostlist_t newhosts = hostlist_create(NULL); char *host; /* Put the expansion of any aliases in the hostlist into 'newhosts', * deleting the original reference from the hostlist. */ if (newhosts == NULL) err_exit(false, "hostlist_create failed"); if ((itr = hostlist_iterator_create(hl)) == NULL) err_exit(false, "hostlist_iterator_create failed"); while ((host = hostlist_next(itr)) != NULL) { alias_t *a; a = list_find_first(conf_aliases, (ListFindF) _alias_match, host); if (a) { hostlist_delete_host(hl, host); hostlist_push_list(newhosts, a->hl); hostlist_iterator_reset(itr); /* not sure of itr position after insertion/deletion so reset */ } free(host); } hostlist_iterator_destroy(itr); /* dump the contents of 'newhosts' into the hostlist */ hostlist_push_list(hl, newhosts); hostlist_destroy(newhosts); } static void _alias_destroy(alias_t *a) { if (a->name) xfree(a->name); if (a->hl) hostlist_destroy(a->hl); xfree(a); } static alias_t *_alias_create(char *name, char *hosts) { alias_t *a = NULL; if (!list_find_first(conf_aliases, (ListFindF) _alias_match, name)) { a = (alias_t *)xmalloc(sizeof(alias_t)); a->name= xstrdup(name); a->hl = hostlist_create(hosts); if (a->hl == NULL) { _alias_destroy(a); a = NULL; } } return a; } /* * Called from the parser. */ bool conf_add_alias(char *name, char *hosts) { alias_t *a; if ((a = _alias_create(name, hosts))) { list_push(conf_aliases, a); return true; } return false; } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/parse_util.h000066400000000000000000000017721467035776500203430ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_PARSE_UTIL_H #define PM_PARSE_UTIL_H #include void conf_init(char *filename); void conf_fini(void); bool conf_addnodes(char *nodelist); bool conf_node_exists(char *node); hostlist_t conf_getnodes(void); bool conf_get_use_tcp_wrappers(void); void conf_set_use_tcp_wrappers(bool val); int conf_get_plug_log_level(void); void conf_set_plug_log_level(char *level); List conf_get_listen(void); void conf_add_listen(char *hostport); void conf_exp_aliases(hostlist_t hl); bool conf_add_alias(char *name, char *hosts); #endif /* PM_PARSE_UTIL_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/pluglist.c000066400000000000000000000151061467035776500200260ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include "list.h" #include "xmalloc.h" #include "hostlist.h" #include "pluglist.h" struct pluglist_iterator { ListIterator itr; }; struct pluglist { List pluglist; bool hardwired; }; static Plug *_create_plug(char *name) { Plug *plug = (Plug *) xmalloc(sizeof(Plug)); assert(name != NULL); plug->name = xstrdup(name); plug->node = NULL; return plug; } static Plug *_copy_plug(Plug *p) { Plug *plug = (Plug *) xmalloc(sizeof(Plug)); assert(p != NULL); plug->name = p->name ? xstrdup(p->name) : NULL; plug->node = p->node ? xstrdup(p->node) : NULL; return plug; } static void _destroy_plug(Plug *plug) { assert(plug != NULL); xfree(plug->name); if (plug->node) xfree(plug->node); xfree(plug); } PlugList pluglist_create(List plugnames) { PlugList pl = (PlugList) xmalloc(sizeof(struct pluglist)); pl->pluglist = list_create((ListDelF)_destroy_plug); pl->hardwired = false; /* create plug for each element of plugnames list */ if (plugnames) { ListIterator itr; char *name; itr = list_iterator_create(plugnames); while ((name = list_next(itr))) list_append(pl->pluglist, _create_plug(name)); list_iterator_destroy(itr); pl->hardwired = true; } return pl; } PlugList pluglist_copy_from_list(List plugs) { PlugList pl = (PlugList) xmalloc(sizeof(struct pluglist)); pl->pluglist = list_create((ListDelF)_destroy_plug); pl->hardwired = false; /* create plug from each plug in list */ if (plugs) { ListIterator itr; Plug *p; itr = list_iterator_create(plugs); while ((p = list_next(itr))) { list_append(pl->pluglist, _copy_plug(p)); } list_iterator_destroy(itr); pl->hardwired = true; } return pl; } void pluglist_destroy(PlugList pl) { assert(pl != NULL); list_destroy(pl->pluglist); xfree(pl); } static Plug *_pluglist_find_any(PlugList pl, char *name) { PlugListIterator itr = pluglist_iterator_create(pl); Plug *plug; while ((plug = pluglist_next(itr))) { if (strcmp(plug->name, name) == 0) break; } pluglist_iterator_destroy(itr); return plug; } /* Assign a node name to an existing Plug. * Create Plug if Plug with name doesn't exist and Plugs are not hardwired. */ static pl_err_t _pluglist_map_one(PlugList pl, char *node, char *name) { Plug *plug = _pluglist_find_any(pl, name); pl_err_t res = EPL_SUCCESS; if (plug == NULL) { if (pl->hardwired) { res = EPL_UNKPLUG; goto err; } plug = _create_plug(name); list_push(pl->pluglist, plug); } if (plug->node) { res = EPL_DUPPLUG; goto err; } plug->node = xstrdup(node); err: return res; } /* Assign a node name to the next available plug. */ static pl_err_t _pluglist_map_next(PlugList pl, char *node) { Plug *plug; PlugListIterator pitr; pl_err_t res = EPL_NOPLUGS; pitr = pluglist_iterator_create(pl); while ((plug = pluglist_next(pitr))) { if (plug->node == NULL) { plug->node = xstrdup(node); res = EPL_SUCCESS; break; } } pluglist_iterator_destroy(pitr); return res; } pl_err_t pluglist_map(PlugList pl, char *nodelist, char *pluglist) { pl_err_t res = EPL_SUCCESS; assert(pl != NULL); assert(nodelist != NULL); /* If pluglist is omitted we have one of two cases: * 1) hardwired plugs, and we assign node names to existing plugs in order. * 2) no plugs, we create plugs with same names as node names. */ if (pluglist == NULL) { hostlist_t nhl = hostlist_create(nodelist); hostlist_iterator_t nitr = hostlist_iterator_create(nhl); char *node; while ((node = hostlist_next(nitr))) { if (pl->hardwired) res = _pluglist_map_next(pl, node); else res = _pluglist_map_one(pl, node, node); free(node); if (res != EPL_SUCCESS) break; } hostlist_iterator_destroy(nitr); hostlist_destroy(nhl); /* We have a pluglist so we just map plugs to nodes. */ } else { hostlist_t nhl = hostlist_create(nodelist); hostlist_iterator_t nitr = hostlist_iterator_create(nhl); hostlist_t phl = hostlist_create(pluglist); hostlist_iterator_t pitr = hostlist_iterator_create(phl); char *node, *name; while ((node = hostlist_next(nitr))) { name = hostlist_next(pitr); if (name) res = _pluglist_map_one(pl, node, name); else res = EPL_NOPLUGS; free(node); free(name); if (res != EPL_SUCCESS) break; } if (res == EPL_SUCCESS) { char *tmp = hostlist_next(pitr); if (tmp != NULL) res = EPL_NONODES; free(tmp); } hostlist_iterator_destroy(pitr); hostlist_iterator_destroy(nitr); hostlist_destroy(phl); hostlist_destroy(nhl); } return res; } PlugListIterator pluglist_iterator_create(PlugList pl) { PlugListIterator itr = (PlugListIterator)xmalloc(sizeof(struct pluglist_iterator)); itr->itr = list_iterator_create(pl->pluglist); return itr; } void pluglist_iterator_destroy(PlugListIterator itr) { assert(itr != NULL); list_iterator_destroy(itr->itr); xfree(itr); } Plug *pluglist_next(PlugListIterator itr) { assert(itr != NULL); return (Plug *)list_next(itr->itr); } Plug *pluglist_find(PlugList pl, char *name) { Plug *plug; assert(pl != NULL); assert(name != NULL); plug = _pluglist_find_any(pl, name); if (plug && plug->node == NULL) plug = NULL; return plug; } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/pluglist.h000066400000000000000000000045511467035776500200350ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_PLUGLIST_H #define PM_PLUGLIST_H /* * Pluglists are used to map node names to plug names within a given device * context. */ typedef struct { char *name; /* how the plug is known to the device */ char *node; /* node name */ } Plug; typedef struct pluglist_iterator *PlugListIterator; typedef struct pluglist *PlugList; typedef enum { EPL_SUCCESS, EPL_DUPNODE, EPL_UNKPLUG, EPL_DUPPLUG, EPL_NOPLUGS, EPL_NONODES } pl_err_t; /* Create a PlugList. plugnames may be NULL (indicating plug creation is * deferred until pluglist_map() time), or a hardwired list of plug names. * ('hardwired' means the list of plugnames is fixed at creation time). */ PlugList pluglist_create(List plugnames); /* Create a PlugList, copying plugs from an existing list of plugs */ PlugList pluglist_copy_from_list(List plugs); /* Destroy a PlugList and its Plugs */ void pluglist_destroy(PlugList pl); /* Assign node names to plugs. nodelist and pluglist are strings in compressed * hostlist format (the degenerate case of which is a single name). pluglist * can be NULL, indicating * - if hardwired plugs, available plugs should be assigned to nodes in order * - else (not hardwired), assume plug names are the same as node names. */ pl_err_t pluglist_map(PlugList pl, char *nodelist, char *pluglist); /* Search PlugList for a Plug with matching plug name. Return pointer to Plug * on success (points to actual list entry), or NULL on search failure. * Only plugs with non-NULL node fields are returned. */ Plug * pluglist_find(PlugList pl, char *name); /* An iterator interface for PlugLists, similar to the iterators in list.h. */ PlugListIterator pluglist_iterator_create(PlugList pl); void pluglist_iterator_destroy(PlugListIterator itr); Plug * pluglist_next(PlugListIterator itr); #endif /* PM_PLUGLIST_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/powerman.c000066400000000000000000000346311467035776500200170ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #if HAVE_GENDERS_H #include #endif #include #include #include #include #include #include #include #include #include #include #include "powerman.h" #include "xmalloc.h" #include "xread.h" #include "error.h" #include "hostlist.h" #include "client_proto.h" #include "debug.h" #include "argv.h" #include "fdutil.h" #include "hprintf.h" #include "argv.h" #include "list.h" #if WITH_GENDERS static void _push_genders_hosts(hostlist_t targets, char *s); #endif static int _connect_to_server_tcp(char *host, char *port, int retries); static void _usage(void); static void _license(void); static void _version(void); static int _process_line(int fd); static void _expect(int fd, char *str); static int _process_response(int fd); static void _process_version(int fd); static void _set_command (const char **command, const char *value); static char *prog; #define OPTIONS "01crfubqtldTxgh:VLR:H" static const struct option longopts[] = { // command {"on", no_argument, 0, '1'}, {"off", no_argument, 0, '0'}, {"cycle", no_argument, 0, 'c'}, {"reset", no_argument, 0, 'r'}, {"flash", no_argument, 0, 'f'}, {"unflash", no_argument, 0, 'u'}, {"beacon", no_argument, 0, 'b'}, {"query", no_argument, 0, 'q'}, {"temp", no_argument, 0, 't'}, {"list", no_argument, 0, 'l'}, {"device", no_argument, 0, 'd'}, // options {"telemetry", no_argument, 0, 'T'}, {"exprange", no_argument, 0, 'x'}, {"genders", no_argument, 0, 'g'}, {"server-host", required_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"license", no_argument, 0, 'L'}, {"retry-connect", required_argument, 0, 'R'}, {"help", no_argument, 0, 'H'}, {0, 0, 0, 0}, }; int main(int argc, char **argv) { int c; int res = 0; int server_fd; char *p, *port = DFLT_PORT; char *host = DFLT_HOSTNAME; bool genders = false; unsigned long retry_connect = 0; const char *command = NULL; bool telemetry = false; bool exprange = false; hostlist_t targets; bool targets_required = false; prog = basename(argv[0]); err_init(prog); targets = hostlist_create(NULL); /* Parse options. */ opterr = 0; while ((c = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) { switch (c) { case '1': /* --on */ _set_command(&command, CP_ON); targets_required = true; break; case '0': /* --off */ _set_command(&command, CP_OFF); targets_required = true; break; case 'c': /* --cycle */ _set_command(&command, CP_CYCLE); targets_required = true; break; case 'r': /* --reset */ _set_command(&command, CP_RESET); targets_required = true; break; case 'l': /* --list */ _set_command(&command, CP_NODES); break; case 'q': /* --query */ _set_command(&command, CP_STATUS); break; case 'f': /* --flash */ _set_command(&command, CP_BEACON_ON); targets_required = true; break; case 'u': /* --unflash */ _set_command(&command, CP_BEACON_OFF); targets_required = true; break; case 'b': /* --beacon */ _set_command(&command, CP_BEACON); break; case 't': /* --temp */ _set_command(&command, CP_TEMP); break; case 'd': /* --device */ _set_command(&command, CP_DEVICE); break; case 'h': /* --server-host host[:port] */ if ((p = strchr(optarg, ':'))) { *p++ = '\0'; port = p; } host = optarg; break; case 'L': /* --license */ _license(); /*NOTREACHED*/ break; case 'V': /* --version */ _version(); /*NOTREACHED*/ break; case 'T': /* --telemetry */ telemetry = true; break; case 'x': /* --exprange */ exprange = true; break; case 'g': /* --genders */ #if WITH_GENDERS genders = true; #else err_exit(false, "not configured with genders support"); #endif break; case 'R': /* --retry-connect=N (sleep 100ms after fail) */ errno = 0; retry_connect = strtoul (optarg, NULL, 10); if (errno != 0 || retry_connect < 1) err_exit(false, "invalid --retry-connect argument"); break; case 'H': /* --help */ _usage(); /*NOTREACHED*/ default: err_exit(false, "Unknown option. Try '--help' for more information."); /*NOTREACHED*/ break; } } if (!command) err_exit(false, "No action was specified."); /* Combine free arguments into target hostlist. * If --genders was selected, convert to hosts. * Then convert back to a single hostlist-compressed argument. * If there were no arguments, the result is the empty string. */ while (optind < argc) { if (!genders) { if (!hostlist_push(targets, argv[optind++])) err_exit(false, "hostlist error"); } #if WITH_GENDERS else _push_genders_hosts(targets, argv[optind++]); #endif } char argument[CP_LINEMAX]; if (hostlist_ranged_string(targets, sizeof(argument), argument) == -1) err_exit(false, "hostlist error"); /* Now that free arguments have been processed, * Fail if 'command' doesn't accept an argument (%s) but there is one, * or if the command requires an argument and there isn't one. */ if (!strstr(command, "%s") && strlen (argument) > 0) // e.g. --nodes err_exit(false, "Command does not accept targets"); if (targets_required && strlen (argument) == 0) err_exit(false, "Command requires targets"); /* Establish connection to server and start protocol. */ server_fd = _connect_to_server_tcp(host, port, retry_connect); _process_version(server_fd); _expect(server_fd, CP_PROMPT); /* First send commands that set options. */ if (telemetry) { hfdprintf(server_fd, "%s%s" , CP_TELEMETRY, CP_EOL); res = _process_response(server_fd); _expect(server_fd, CP_PROMPT); if (res != 0) goto done; } if (exprange) { hfdprintf(server_fd, "%s%s", CP_EXPRANGE, CP_EOL); res = _process_response(server_fd); _expect(server_fd, CP_PROMPT); if (res != 0) goto done; } /* Send the main command. * Use 'command' as the format string if it contains '%s' for an argument. */ if (strstr (command, "%s")) { hfdprintf(server_fd, command, argument); hfdprintf(server_fd, CP_EOL); } else hfdprintf(server_fd, "%s%s", command, CP_EOL); res = _process_response(server_fd); _expect(server_fd, CP_PROMPT); /* Disconnect from server. */ done: hfdprintf(server_fd, "%s%s", CP_QUIT, CP_EOL); _expect(server_fd, CP_RSP_QUIT); exit(res); } /* Display powerman usage and exit. */ static void _usage(void) { printf("Usage: %s [options] [command] [targets]\n", prog); printf( "Commands:\n" " -1,--on Power on targets\n" " -0,--off Power off targets\n" " -c,--cycle Power cycle targets\n" " -q,--query Query power state on optional targets\n" " -r,--reset Assert hardware reset on targets\n" " -f,--flash Turn beacon on on targets\n" " -u,--unflash Turn beacon off on targets\n" " -b,--beacon Query beacon status on optional targets\n" " -P,--temp Query temperature on optional targets\n" " -l,--list List available targets\n" " -d,--device Show status of devices that control optional targets\n" "Options:\n" #if WITH_GENDERS " -g,--genders Interpret targets as attributes\n" #endif " -h,--server-host host[:port]\n" " Connect to remote server\n" " -x,--exprange Expand host ranges in query response\n" " -V,--version Show powerman version\n" " -L,--license Show powerman license\n" " -T,--telemtery Show device conversation for debugging\n" " -R,--retry-connect=N Retry connect to server up to N times\n" ); exit(0); } /* Display powerman license and exit. */ static void _license(void) { printf( "Copyright (C) 2001 The Regents of the University of California.\n" "(c.f. DISCLAIMER, COPYING)\n" "\n" "This file is part of Powerman, a remote power management program.\n" "For details, see https://github.com/chaos/powerman.\n" "\n" "SPDX-License-Identifier: GPL-2.0-or-later\n"); exit(0); } /* Display powerman version and exit. */ static void _version(void) { printf("%s\n", PACKAGE_VERSION); exit(0); } static void _set_command (const char **command, const char *value) { if (*command) err_exit(false, "Only one action may be specified"); *command = value; } #if WITH_GENDERS static void _push_genders_hosts(hostlist_t targets, char *s) { genders_t g; char **nodes; int len, n, i; if (strlen(s) == 0) return; if (!(g = genders_handle_create())) err_exit(false, "genders_handle_create failed"); if (genders_load_data(g, NULL) < 0) err_exit(false, "genders_load_data: %s", genders_errormsg(g)); if ((len = genders_nodelist_create(g, &nodes)) < 0) err_exit(false, "genders_nodelist_create: %s", genders_errormsg(g)); if ((n = genders_query(g, nodes, len, s)) < 0) err_exit(false, "genders_query: %s", genders_errormsg(g)); genders_handle_destroy(g); if (n == 0) err_exit(false, "genders expression did not match any nodes"); for (i = 0; i < n; i++) { if (!hostlist_push(targets, nodes[i])) err_exit(false, "hostlist error"); } } #endif static int _connect_any(struct addrinfo *addr) { struct addrinfo *r; int fd = -1; for (r = addr; r != NULL; r = r->ai_next) { if ((fd = socket(r->ai_family, r->ai_socktype, 0)) < 0) continue; if (connect(fd, r->ai_addr, r->ai_addrlen) < 0) { close(fd); fd = -1; continue; } break; /* success! */ } return fd; } static int _connect_to_server_tcp(char *host, char *port, int retries) { int error, fd = -1; struct addrinfo hints, *res; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if ((error = getaddrinfo(host, port, &hints, &res)) != 0) err_exit(false, "getaddrinfo %s:%s: %s", host, port, gai_strerror(error)); if (res == NULL) err_exit(false, "no addresses for server %s:%s", host, port); while ((fd = _connect_any(res)) < 0 && retries-- > 0) usleep(100000); // 100ms if (fd < 0) err_exit(false, "could not connect to address %s:%s", host, port); freeaddrinfo(res); return fd; } /* Return true if response should be suppressed. */ static bool _suppress(int num) { if (strtol(CP_RSP_QRY_COMPLETE, NULL, 10) == num) return true; if (strtol(CP_RSP_TELEMETRY, NULL, 10) == num) return true; if (strtol(CP_RSP_EXPRANGE, NULL, 10) == num) return true; return false; } static FILE *getstream(int num) { /* diagnostic output goes to stderr */ return (num == 309) ? stderr : stdout; } /* Get a line from the socket and display on stdout. * Return the numerical portion of the response. */ static int _process_line(int fd) { char *buf = xreadstr(fd); long int num; num = strtol(buf, NULL, 10); if (num == LONG_MIN || num == LONG_MAX) num = -1; if (strlen(buf) > 4) { if (!_suppress(num)) fprintf(getstream(num), "%s\n", buf + 4); } else err_exit(false, "unexpected response from server"); xfree(buf); return num; } /* Read version and warn if it doesn't match the client's. */ static void _process_version(int fd) { char *buf = xreadstr(fd); char *vers = xmalloc (strlen(buf)+1); if (sscanf(buf, CP_VERSION, vers) != 1) err_exit(false, "unexpected response from server"); if (strcmp(vers, PACKAGE_VERSION) != 0) err(false, "warning: server version (%s) != client (%s)", vers, PACKAGE_VERSION); xfree(buf); xfree(vers); } static int _process_response(int fd) { int num; do { num = _process_line(fd); } while (!CP_IS_ALLDONE(num)); return (CP_IS_FAILURE(num) ? num : 0); } /* Read strlen(str) bytes from file descriptor and exit if * it doesn't match 'str'. */ static void _expect(int fd, char *str) { int len = strlen(str); char *buf = xmalloc (len + 1); char *p = buf; int res; do { res = xread(fd, p, len); if (res < 0) err_exit(true, "lost connection with server"); p += res; *p = '\0'; len -= res; } while (strcmp(str, buf) != 0 && len > 0); /* Shouldn't happen. We are not handling the general case of the server * returning the wrong response. Read() loop above may hang in that case. */ if (strcmp(str, buf) != 0) err_exit(false, "unexpected response from server"); xfree (buf); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/powerman.h000066400000000000000000000011731467035776500200170ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef PM_POWERMAN_H #define PM_POWERMAN_H #define DAEMON_NAME "powermand" #define DFLT_PORT "10101" #define DFLT_HOSTNAME "127.0.0.1" #endif /* PM_POWERMAN_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/powermand.c000066400000000000000000000126561467035776500201660ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "list.h" #include "hostlist.h" #include "parse_util.h" #include "xmalloc.h" #include "xpoll.h" #include "xsignal.h" #include "pluglist.h" #include "device.h" #include "client.h" #include "error.h" #include "debug.h" #include "hprintf.h" #include "powerman.h" /* prototypes */ static void _usage(char *prog); static void _version(void); static void _noop_handler(int signum); static void _exit_handler(int signum); static void _select_loop(void); static int exitpipe[2]; #define OPTIONS "c:hd:VsY" static const struct option longopts[] = { {"conf", required_argument, 0, 'c'}, {"help", no_argument, 0, 'h'}, {"debug", required_argument, 0, 'd'}, {"version", no_argument, 0, 'V'}, {"stdio", no_argument, 0, 's'}, {"short-circuit-delay", no_argument, 0, 'Y'}, {0, 0, 0, 0} }; int main(int argc, char **argv) { int c; char *config_filename = NULL; bool use_stdio = false; bool short_circuit_delay = false; /* parse command line options */ err_init(argv[0]); while ((c = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) { switch (c) { case 'Y': /* --short-circuit-delay */ short_circuit_delay = true; break; case 'c': /* --conf */ if (!config_filename) config_filename = xstrdup(optarg); break; case 'd': /* --debug */ { unsigned long val = strtol(optarg, NULL, 0); if ((val == LONG_MAX || val == LONG_MIN) && errno == ERANGE) err_exit(true, "strtol on debug mask"); dbg_setmask(val); } break; case 'V': /* --version */ _version(); /*NOTREACHED*/ break; case 's': /* --stdio */ use_stdio = true; break; case 'h': /* --help */ default: _usage(argv[0]); /*NOTREACHED*/ break; } } if (pipe (exitpipe) < 0 || fcntl (exitpipe[0], F_SETFD, O_CLOEXEC) < 0 || fcntl (exitpipe[1], F_SETFD, O_CLOEXEC) < 0) err_exit (true, "could not create pipe for exit signaling"); if (!config_filename) config_filename = hsprintf("%s/%s/%s", X_SYSCONFDIR, "powerman", "powerman.conf"); dev_init(short_circuit_delay); cli_init(); conf_init(config_filename); xfree(config_filename); xsignal(SIGHUP, _noop_handler); xsignal(SIGTERM, _exit_handler); xsignal(SIGINT, _exit_handler); xsignal(SIGPIPE, SIG_IGN); cli_start(use_stdio); /* We now have a socket at listener fd running in listen mode */ /* and a file descriptor for communicating with each device */ _select_loop(); (void)close (exitpipe[0]); (void)close (exitpipe[1]); cli_fini(); dev_fini(); conf_fini(); return 0; } static void _usage(char *prog) { printf("Usage: %s [OPTIONS]\n", prog); printf(" -c,--conf=PATH Specify config file path\n"); printf(" -s,--stdio Talk to client on stdin/stdout\n"); printf(" -Y,--short-circuit-delay Change all device delays to zero\n"); printf(" -d,--debug=MASK Enable debug logging\n"); printf(" -V,--version Report powerman version\n"); printf(" -h,--help Display help\n"); exit(0); } static void _version(void) { printf("%s\n", VERSION); exit(0); } static void _select_loop(void) { struct timeval tmout; xpollfd_t pfd = xpollfd_create(); timerclear(&tmout); /* start non-blocking connections to all the devices - finish them inside * the poll loop. */ dev_initial_connect(); while (1) { xpollfd_zero(pfd); cli_pre_poll(pfd); dev_pre_poll(pfd); xpollfd_set(pfd, exitpipe[0], XPOLLIN); xpoll(pfd, timerisset(&tmout) ? &tmout : NULL); timerclear(&tmout); if (xpollfd_revents(pfd, exitpipe[0])) break; /* * Process activity on client and device fd's. * If a device requires a timeout, for example to reconnect or * to process a scripted delay, tmout is updated. */ cli_post_poll(pfd); dev_post_poll(pfd, &tmout); if (cli_server_done()) break; } xpollfd_destroy(pfd); } static void _noop_handler(int signum) { /* do nothing */ } /* Wake up the select loop so it can exit and allow destructors to be called. */ static void _exit_handler(int signum) { if (write (exitpipe[1], "", 1) != 1) err_exit(true, "signal %d: could not write to exit pipe", signum); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/test/000077500000000000000000000000001467035776500167735ustar00rootroot00000000000000powerman-2.4.4/src/powerman/test/apiclient.c000066400000000000000000000047531467035776500211200ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2008 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* cli.c - simple client to demo the libpowerman api */ #include #include #include "libpowerman.h" static pm_err_t list_nodes(pm_handle_t pm); static void usage(void); #define statstr(s) ((s) == PM_ON ? "on" : (s) == PM_OFF ? "off" : "unknown") int main(int argc, char *argv[]) { pm_err_t err = PM_ESUCCESS; pm_node_state_t ns; pm_handle_t pm; char ebuf[64]; char *server, *node = NULL; char cmd; if (argc < 3 || argc > 4) usage(); server = argv[1]; cmd = argv[2][0]; if (argc == 3 && cmd != 'l') usage(); if (argc == 4 && cmd != '1' && cmd != '0' && cmd != 'c' && cmd != 'q') usage(); if (argc == 4) node = argv[3]; if ((err = pm_connect(server, NULL, &pm, 0)) != PM_ESUCCESS) { fprintf(stderr, "%s: %s\n", server, pm_strerror(err, ebuf, sizeof(ebuf))); exit(1); } switch (cmd) { case '1': err = pm_node_on(pm, node); break; case '0': err = pm_node_off(pm, node); break; case 'c': err = pm_node_cycle(pm, node); break; case 'l': err = list_nodes(pm); break; case 'q': ns = PM_UNKNOWN; if ((err = pm_node_status(pm, node, &ns)) == PM_ESUCCESS) printf("%s: %s\n", node, statstr(ns)); break; } if (err != PM_ESUCCESS) { fprintf(stderr, "Error: %s\n", pm_strerror(err, ebuf, sizeof(ebuf))); pm_disconnect(pm); exit(1); } pm_disconnect(pm); exit(0); } static pm_err_t list_nodes(pm_handle_t pm) { pm_node_iterator_t pmi; pm_err_t err; char *s; if ((err = pm_node_iterator_create(pm, &pmi)) != PM_ESUCCESS) return err; while ((s = pm_node_next(pmi))) printf("%s\n", s); pm_node_iterator_destroy(pmi); return err; } static void usage(void) { fprintf(stderr, "Usage: cli host:port 0|1|q node\n"); fprintf(stderr, " cli host:port l\n"); exit(1); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/powerman/test/pluglist.c000066400000000000000000000050731467035776500210070ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* * Test driver for pluglist module. */ #include #include #include #include #include "list.h" #include "pluglist.h" #include "hostlist.h" #include "error.h" #include "xmalloc.h" void usage(void) { fprintf(stderr, "Usage: tpl [-f plug_to_find] [-p fixed_plugs] nodelist [pluglist]\n"); exit(1); } int main(int argc, char *argv[]) { extern int optind; extern char *optarg; int c; PlugList pl = NULL; char *hwplugs = NULL; char *nodelist = NULL; char *pluglist = NULL; char *findplug = NULL; err_init(basename(argv[0])); while ((c = getopt(argc, argv, "p:f:")) != EOF) { switch (c) { case 'p': hwplugs = optarg; break; case 'f': findplug = optarg; break; default: usage(); } } if (argc - optind == 0) usage(); nodelist = argv[optind++]; if (argc - optind == 1) pluglist = argv[optind++]; if (argc - optind != 0) usage(); if (hwplugs) { hostlist_t hl = hostlist_create(hwplugs); hostlist_iterator_t itr = hostlist_iterator_create(hl); List l = list_create((ListDelF)xfree); char *plug; while ((plug = hostlist_next(itr))) list_append(l, xstrdup(plug)); hostlist_iterator_destroy(itr); hostlist_destroy(hl); pl = pluglist_create(l); list_destroy(l); } else pl = pluglist_create(NULL); switch (pluglist_map(pl, nodelist, pluglist)) { case EPL_DUPNODE: fprintf(stderr, "duplicate node\n"); break; case EPL_UNKPLUG: fprintf(stderr, "unknown plug\n"); break; case EPL_DUPPLUG: fprintf(stderr, "duplicate plug\n"); break; case EPL_NOPLUGS: fprintf(stderr, "more nodes than plugs\n"); break; case EPL_NONODES: fprintf(stderr, "more plugs than nodes\n"); break; case EPL_SUCCESS: break; } if (findplug) { Plug *plug = pluglist_find(pl, findplug); if (plug) printf("plug=%s node=%s\n", plug->name, plug->node ? plug->node : "NULL"); else printf("plug %s: not found\n", findplug); } else { PlugListIterator itr = pluglist_iterator_create(pl); Plug *plug; while ((plug = pluglist_next(itr))) { printf("plug=%s node=%s\n", plug->name, plug->node ? plug->node : "NULL"); } pluglist_iterator_destroy(itr); } exit(0); } powerman-2.4.4/src/redfishpower/000077500000000000000000000000001467035776500166655ustar00rootroot00000000000000powerman-2.4.4/src/redfishpower/Makefile.am000066400000000000000000000016361467035776500207270ustar00rootroot00000000000000AM_CFLAGS = @WARNING_CFLAGS@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/liblsd \ -I$(top_srcdir)/src/libczmq \ -I$(top_srcdir)/src/libcommon sbin_PROGRAMS = redfishpower redfishpower_SOURCES = \ redfishpower.c \ redfishpower_defs.h \ plugs.h \ plugs.c redfishpower_LDADD = \ $(top_builddir)/src/liblsd/liblsd.la \ $(top_builddir)/src/libczmq/libczmq.la \ $(top_builddir)/src/libcommon/libcommon.la \ $(LIBCURL) \ $(LIBJANSSON) TESTS = test_plugs.t check_PROGRAMS = $(TESTS) TEST_EXTENSIONS = .t T_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \ $(top_srcdir)/config/tap-driver.sh test_plugs_t_CPPFLAGS = \ -I$(top_srcdir)/src/liblsd \ -I$(top_srcdir)/src/libtap test_plugs_t_SOURCES = test/plugs.c test_plugs_t_LDADD = \ $(builddir)/plugs.o \ $(top_builddir)/src/libcommon/libcommon.la \ $(top_builddir)/src/liblsd/liblsd.la \ $(top_builddir)/src/libczmq/libczmq.la \ $(top_builddir)/src/libtap/libtap.la powerman-2.4.4/src/redfishpower/plugs.c000066400000000000000000000120601467035776500201620ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2024 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "redfishpower_defs.h" #include "plugs.h" #include "xmalloc.h" #include "czmq.h" #include "hostlist.h" #include "error.h" struct plugs { hostlist_t plugs; /* map plug names to plug_data */ zhashx_t *plug_map; }; static struct plug_data *plug_data_create(const char *plugname, const char *hostname, const char *parent) { struct plug_data *pd = (struct plug_data *)xmalloc(sizeof(*pd)); pd->plugname = xstrdup(plugname); pd->hostname = xstrdup(hostname); if (parent) pd->parent = xstrdup(parent); return pd; } static void plug_data_destroy(struct plug_data *pd) { if (pd) { xfree(pd->plugname); xfree(pd->hostname); xfree(pd->parent); xfree(pd->stat); xfree(pd->on); xfree(pd->onpostdata); xfree(pd->off); xfree(pd->offpostdata); xfree(pd); } } /* zhashx_destructor_fn */ static void plug_data_destroy_wrapper(void **data) { struct plug_data *pd = *data; plug_data_destroy(pd); } plugs_t *plugs_create(void) { plugs_t *p = (plugs_t *)xmalloc(sizeof(*p)); if (!(p->plugs = hostlist_create(NULL))) goto cleanup; if (!(p->plug_map = zhashx_new())) goto cleanup; zhashx_set_destructor(p->plug_map, plug_data_destroy_wrapper); return p; cleanup: plugs_destroy(p); return NULL; } void plugs_destroy(plugs_t *p) { if (p) { hostlist_destroy(p->plugs); zhashx_destroy(&p->plug_map); xfree(p); } } void plugs_add(plugs_t *p, const char *plugname, const char *hostname, const char *parent) { struct plug_data *pd; if (hostlist_find(p->plugs, plugname) < 0) { if (hostlist_push(p->plugs, plugname) == 0) err_exit(false, "hostlist_push failed"); } pd = plug_data_create(plugname, hostname, parent); zhashx_update(p->plug_map, plugname, pd); } void plugs_remove(plugs_t *p, const char *plugname) { zhashx_delete(p->plug_map, plugname); hostlist_delete(p->plugs, plugname); } int plugs_count(plugs_t *p) { return hostlist_count(p->plugs); } struct plug_data *plugs_get_data(plugs_t *p, const char *plugname) { return zhashx_lookup(p->plug_map, plugname); } hostlist_t *plugs_hostlist(plugs_t *p) { return &p->plugs; } int plugs_update_path(plugs_t *p, const char *plugname, const char *cmd, const char *path, const char *postdata) { struct plug_data *pd; char **cmdptr = NULL; char **postdataptr = NULL; if (!(pd = plugs_get_data(p, plugname))) return -1; if (strcmp(cmd, CMD_STAT) == 0) { cmdptr = &pd->stat; } else if (strcmp(cmd, CMD_ON) == 0) { cmdptr = &pd->on; postdataptr = &pd->onpostdata; } else if (strcmp(cmd, CMD_OFF) == 0) { cmdptr = &pd->off; postdataptr = &pd->offpostdata; } else return -1; if (*cmdptr) { free(*cmdptr); (*cmdptr) = NULL; } if (postdataptr && *postdataptr) { free(*postdataptr); (*postdataptr) = NULL; } if (path) { (*cmdptr) = xstrdup(path); if (postdataptr && postdata) (*postdataptr) = xstrdup(postdata); } return 0; } int plugs_name_valid(plugs_t *p, const char *plugname) { if (hostlist_find(p->plugs, plugname) < 0) return 0; return 1; } char *plugs_find_root_parent(plugs_t *p, const char *plugname) { struct plug_data *pd = zhashx_lookup(p->plug_map, plugname); if (!pd) return NULL; do { if (!pd->parent) return pd->plugname; if (!(pd = zhashx_lookup(p->plug_map, pd->parent))) return NULL; } while (pd); /* NOT REACHED */ return NULL; } int plugs_is_descendant(plugs_t *p, const char *plugname, const char *ancestor) { return plugs_child_of_ancestor(p, plugname, ancestor) ? 1 : 0; } char *plugs_child_of_ancestor(plugs_t *p, const char *plugname, const char *ancestor) { struct plug_data *pd = zhashx_lookup(p->plug_map, plugname); if (!pd) return NULL; while (pd->parent) { if (strcmp(pd->parent, ancestor) == 0) return pd->plugname; if (!(pd = zhashx_lookup(p->plug_map, pd->parent))) return NULL; } return NULL; } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/redfishpower/plugs.h000066400000000000000000000040411467035776500201670ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2024 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef REDFISHPOWER_PLUGS_H #define REDFISHPOWER_PLUGS_H #include "hostlist.h" struct plug_data { char *plugname; char *hostname; char *parent; /* NULL if no parent */ /* paths */ char *stat; char *on; char *onpostdata; char *off; char *offpostdata; char *cycle; char *cyclepostdata; }; typedef struct plugs plugs_t; plugs_t *plugs_create(void); void plugs_destroy(plugs_t *p); void plugs_add(plugs_t *p, const char *plugname, const char *hostname, const char *parent); void plugs_remove(plugs_t *p, const char *plugname); int plugs_count(plugs_t *p); struct plug_data *plugs_get_data(plugs_t *p, const char *plugname); hostlist_t *plugs_hostlist(plugs_t *p); int plugs_update_path(plugs_t *p, const char *plugname, const char *cmd, const char *path, const char *postdata); int plugs_name_valid(plugs_t *p, const char *plugname); /* hierarchy * - assumption, user does not introduce loops in config */ /* find deepest ancestor parent for this plugname */ char *plugs_find_root_parent(plugs_t *p, const char *plugname); /* is plugname a descendant of ancestor */ int plugs_is_descendant(plugs_t *p, const char *plugname, const char *ancestor); /* find child of ancestor, starting at plugname */ char *plugs_child_of_ancestor(plugs_t *p, const char *plugname, const char *ancestor); #endif /* REDFISHPOWER_PLUGS_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/redfishpower/redfishpower.c000066400000000000000000001747311467035776500215470ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2021 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "redfishpower_defs.h" #include "plugs.h" #include "xmalloc.h" #include "czmq.h" #include "hostlist.h" #include "error.h" #include "argv.h" static hostlist_t hosts = NULL; static plugs_t *plugs = NULL; /* flag to indicate if we wiped initial plugs */ static int initial_plugs_setup = 0; static char *header = NULL; static struct curl_slist *header_list = NULL; static int resolve_hosts = 0; static int verbose = 0; static char *userpwd = NULL; static int userpwd_set_on_cmdline = 0; /* default paths if host specific ones not set */ static char *statpath = NULL; static char *onpath = NULL; static char *onpostdata = NULL; static char *offpath = NULL; static char *offpostdata = NULL; /* activecmds - power ops to be sent / in progress now */ static zlistx_t *activecmds = NULL; /* delayedcmds - power ops waiting to be sent * - typically holds status polling ops after an on / off, we wait to * send at a later time. */ static zlistx_t *delayedcmds = NULL; /* waitcmds - power ops waiting for a parent check to be completed */ static zlistx_t *waitcmds = NULL; static int test_mode = 0; static hostlist_t test_fail_power_cmd_hosts; static zhashx_t *test_power_status; static zhashx_t *resolve_hosts_cache = NULL; /* in seconds */ #define MESSAGE_TIMEOUT_DEFAULT 10 #define CMD_TIMEOUT_DEFAULT 60 /* Per documentation, wait incremental time then proceed if timeout < 0 */ #define INCREMENTAL_WAIT 500 /* in usec */ #define STATUS_POLLING_INTERVAL_DEFAULT 1000000 #define MS_IN_SEC 1000 #define STATUS_ON "on" #define STATUS_OFF "off" #define STATUS_PAUSED "Paused" #define STATUS_POWERING_ON "PoweringOn" #define STATUS_POWERING_OFF "PoweringOff" #define STATUS_UNKNOWN "unknown" #define STATUS_ERROR "error" #define OUTPUT_RESULT 1 #define NO_OUTPUT 0 /* achu: max length IPv6 is 45 chars, add +1 for NUL * ABCD:ABCD:ABCD:ABCD:ABCD:ABCD:192.168.100.200 */ #ifndef INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN 46 #endif enum { STATE_SEND_POWERCMD, /* stat, on, off */ STATE_WAIT_UNTIL_ON_OFF, /* on, off */ }; struct powermsg { CURLM *mh; /* curl multi handle pointer */ CURL *eh; /* curl easy handle */ char *cmd; /* "on", "off", or "stat" */ char *hostname; /* host we're working with */ char *plugname; /* plugname, in some cases == hostname */ char *parent; /* parent, NULL if no parent */ char *url; /* on, off, stat */ char *postdata; /* on, off */ char *output; /* on, off, stat */ size_t output_len; int output_result; /* output result or not */ int state; /* start - when power op started, may be set to start time of a * previous message if this is a follow on message. * * timeout - when the overall power command times out * * delaystart - if message should be sent after a wait * * poll_count - number of poll attempts */ struct timeval start; struct timeval timeout; struct timeval delaystart; int poll_count; /* zlistx handle */ void *handle; }; #define Curl_easy_setopt(args) \ do { \ CURLcode _ec; \ if ((_ec = curl_easy_setopt args) != CURLE_OK) \ err_exit(false, "curl_easy_setopt: %s", curl_easy_strerror(_ec)); \ } while(0) #define OPTIONS "h:A:H:S:O:F:P:G:m:TEv" static struct option longopts[] = { {"hostname", required_argument, 0, 'h' }, {"header", required_argument, 0, 'H' }, {"auth", required_argument, 0, 'A' }, {"statpath", required_argument, 0, 'S' }, {"onpath", required_argument, 0, 'O' }, {"offpath", required_argument, 0, 'F' }, {"onpostdata", required_argument, 0, 'P' }, {"offpostdata", required_argument, 0, 'G' }, {"message-timeout", required_argument, 0, 'm' }, {"resolve-hosts", no_argument, 0, 'o' }, {"test-mode", no_argument, 0, 'T' }, {"test-fail-power-cmd-hosts", required_argument, 0, 'E' }, {"verbose", no_argument, 0, 'v' }, {0,0,0,0}, }; static time_t cmd_timeout = CMD_TIMEOUT_DEFAULT; /* typically is of type suseconds_t, but has questionable portability, * so use 'long int' instead */ static long int status_polling_interval = STATUS_POLLING_INTERVAL_DEFAULT; static long message_timeout = MESSAGE_TIMEOUT_DEFAULT; void help(void) { printf("Valid commands are:\n"); printf(" auth user:passwd\n"); printf(" setheader string\n"); printf(" setstatpath path\n"); printf(" setonpath path [postdata]\n"); printf(" setoffpath path [postdata]\n"); printf(" setplugs plugnames hostindices [stat) lpath = pd->stat; else lpath = statpath; } else if (strcmp(cmd, CMD_ON) == 0) { if (pd && pd->on) { lpath = pd->on; lpostdata = pd->onpostdata; } else { lpath = onpath; lpostdata = onpostdata; } } else if (strcmp(cmd, CMD_OFF) == 0) { if (pd && pd->off) { lpath = pd->off; lpostdata = pd->offpostdata; } else { lpath = offpath; lpostdata = offpostdata; } } if (lpath) (*path) = calc_path(lpath, plugname); if (lpostdata) (*postdata) = xstrdup(lpostdata); } static size_t output_cb(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct powermsg *pm = userp; if (pm->output) { char *tmp = calloc(1, pm->output_len + realsize + 1); if (!tmp) err_exit(true, "calloc"); memcpy(tmp, pm->output, pm->output_len); memcpy(tmp + pm->output_len, contents, realsize); pm->output_len += realsize; free(pm->output); pm->output = tmp; } else { if (!(pm->output = calloc(1, realsize + 1))) err_exit(true, "calloc"); memcpy(pm->output, contents, realsize); pm->output_len = realsize; } return realsize; } /* called before putting powermsg on activecmds list */ static void powermsg_init_curl(struct powermsg *pm) { CURLMcode mc; if (test_mode) return; if ((pm->eh = curl_easy_init()) == NULL) err_exit(false, "curl_easy_init failed"); /* Per documentation, CURLOPT_TIMEOUT overrides * CURLOPT_CONNECTTIMEOUT */ Curl_easy_setopt((pm->eh, CURLOPT_TIMEOUT, message_timeout)); Curl_easy_setopt((pm->eh, CURLOPT_FAILONERROR, 1)); /* for time being */ Curl_easy_setopt((pm->eh, CURLOPT_SSL_VERIFYPEER, 0L)); Curl_easy_setopt((pm->eh, CURLOPT_SSL_VERIFYHOST, 0L)); if (verbose > 2) Curl_easy_setopt((pm->eh, CURLOPT_VERBOSE, 1L)); if (header) { if (!header_list) { if (!(header_list = curl_slist_append(header_list, header))) err_exit(false, "curl_slist_append"); } Curl_easy_setopt((pm->eh, CURLOPT_HTTPHEADER, header_list)); } if (userpwd) { Curl_easy_setopt((pm->eh, CURLOPT_USERPWD, userpwd)); Curl_easy_setopt((pm->eh, CURLOPT_HTTPAUTH, CURLAUTH_BASIC)); } Curl_easy_setopt((pm->eh, CURLOPT_WRITEFUNCTION, output_cb)); Curl_easy_setopt((pm->eh, CURLOPT_WRITEDATA, (void *)pm)); Curl_easy_setopt((pm->eh, CURLOPT_PRIVATE, pm)); if ((mc = curl_multi_add_handle(pm->mh, pm->eh)) != CURLM_OK) err_exit(false, "curl_multi_add_handle: %s", curl_multi_strerror(mc)); Curl_easy_setopt((pm->eh, CURLOPT_URL, pm->url)); if (pm->postdata) { Curl_easy_setopt((pm->eh, CURLOPT_POST, 1)); Curl_easy_setopt((pm->eh, CURLOPT_POSTFIELDS, pm->postdata)); Curl_easy_setopt((pm->eh, CURLOPT_POSTFIELDSIZE, strlen(pm->postdata))); } else Curl_easy_setopt((pm->eh, CURLOPT_HTTPGET, 1)); } static char *resolve_hosts_url(const char *hostname, const char *path) { char *url; char ipstr[INET6_ADDRSTRLEN] = {0}; size_t len; struct addrinfo *ai; struct addrinfo *res = NULL; int ret; char *ptr; if ((ptr = zhashx_lookup(resolve_hosts_cache, hostname))) { len = strlen("https://") + strlen(ptr) + strlen(path) + 2; url = xmalloc(len); sprintf(url, "https://%s/%s", ptr, path); return url; } if ((ret = getaddrinfo(hostname, NULL, NULL, &res))) err_exit(false, "getaddrinfo: %s", gai_strerror (ret)); for (ai = res; ai != NULL; ai = ai->ai_next) { if (ai->ai_family == AF_INET) { struct sockaddr_in addr; memcpy(&addr, ai->ai_addr, ai->ai_addrlen); if (!inet_ntop (AF_INET, &addr.sin_addr, ipstr, INET6_ADDRSTRLEN)) err_exit(true, "inet_ntop"); if (zhashx_insert(resolve_hosts_cache, hostname, xstrdup(ipstr)) < 0) err_exit(false, "zhashx_insert"); len = strlen("https://") + strlen(ipstr) + strlen(path) + 2; url = xmalloc(len); sprintf(url, "https://%s/%s", ipstr, path); goto out; } else if (ai->ai_family == AF_INET6) { struct sockaddr_in6 addr6; memcpy(&addr6, ai->ai_addr, ai->ai_addrlen); if (!inet_ntop (AF_INET6, &addr6.sin6_addr, ipstr, INET6_ADDRSTRLEN)) err_exit(true, "inet_ntop"); if (zhashx_insert(resolve_hosts_cache, hostname, xstrdup(ipstr)) < 0) err_exit(false, "zhashx_insert"); len = strlen("https://") + strlen(ipstr) + strlen(path) + 2; url = xmalloc(len); sprintf(url, "https://%s/%s", ipstr, path); goto out; } } /* couldn't find? use host */ url = xmalloc(strlen("https://") + strlen(hostname) + strlen(path) + 2); sprintf(url, "https://%s/%s", hostname, path); out: freeaddrinfo(res); return url; } static struct powermsg *powermsg_create(CURLM *mh, const char *hostname, const char *plugname, const char *parent, const char *cmd, const char *path, const char *postdata, struct timeval *start, long int delay_usec, int poll_count, int output_result, int state) { struct powermsg *pm = calloc(1, sizeof(*pm)); struct timeval now; struct timeval waitdelay = { 0 }; if (!pm) err_exit(true, "calloc"); pm->mh = mh; pm->state = state; pm->cmd = xstrdup(cmd); pm->hostname = xstrdup(hostname); pm->plugname = xstrdup(plugname); if (parent) pm->parent = xstrdup(parent); pm->output_result = output_result; if (resolve_hosts) pm->url = resolve_hosts_url(hostname, path); else { pm->url = xmalloc(strlen("https://") + strlen(hostname) + strlen(path) + 2); sprintf(pm->url, "https://%s/%s", hostname, path); } if (postdata) pm->postdata = xstrdup(postdata); if (start) { pm->start.tv_sec = start->tv_sec; pm->start.tv_usec = start->tv_usec; } else gettimeofday(&pm->start, NULL); if (cmd_timeout > (LONG_MAX - pm->start.tv_sec)) err_exit(false, "cmd_timeout overflow"); pm->timeout.tv_sec = pm->start.tv_sec + cmd_timeout; pm->timeout.tv_usec = pm->start.tv_usec; if (delay_usec) { gettimeofday(&now, NULL); waitdelay.tv_usec = delay_usec; timeradd(&now, &waitdelay, &pm->delaystart); } pm->poll_count = poll_count; return pm; } static void powermsg_destroy(struct powermsg *pm) { if (pm) { xfree(pm->cmd); xfree(pm->hostname); xfree(pm->plugname); xfree(pm->parent); xfree(pm->url); xfree(pm->postdata); free(pm->output); if (!test_mode && pm->eh) { CURLMcode mc; Curl_easy_setopt((pm->eh, CURLOPT_URL, "")); if ((mc = curl_multi_remove_handle(pm->mh, pm->eh)) != CURLM_OK) err_exit(false, "curl_multi_remove_handle: %s", curl_multi_strerror(mc)); curl_easy_cleanup(pm->eh); } free(pm); } } static struct powermsg *stat_cmd_plug(CURLM * mh, char *plugname, int output_result) { struct powermsg *pm; struct plug_data *pd; char *path = NULL; if (!(pd = plugs_get_data(plugs, plugname))) { printf("plug not mapped: %s\n", plugname); return NULL; } get_path(CMD_STAT, plugname, &path, NULL); if (!path) { printf("%s: %s path not set\n", plugname, CMD_STAT); return NULL; } pm = powermsg_create(mh, pd->hostname, plugname, pd->parent, CMD_STAT, path, NULL, NULL, 0, 0, output_result, STATE_SEND_POWERCMD); if (verbose > 1) printf("DEBUG: %s hostname=%s plugname=%s path=%s\n", CMD_STAT, pd->hostname, plugname, path); free(path); return pm; } /* is parent plugname already active? * - if command is "on"/"off"/"stat" and plugname command is "stat', * counts as active * - if command is "off" and plugname being turned off, counts as active * * - note, we do not support command "on" and plugname being turned on is "on. * see notes in phased_power_on_check(). */ static int plugname_active(const char *plugname, const char *cmd) { struct powermsg *pm = zlistx_first(activecmds); while (pm) { if (strcmp(pm->plugname, plugname) == 0) { if (strcmp(pm->cmd, CMD_STAT) == 0) return 1; else if (strcmp(cmd, CMD_OFF) == 0 && strcmp(pm->cmd, CMD_OFF) == 0) return 1; } pm = zlistx_next(activecmds); } return 0; } static void send_initial_parent_queries(CURLM *mh) { /* Only send out one query for identical ancestors */ struct powermsg *pm = zlistx_first(waitcmds); while (pm) { char *root_plugname = plugs_find_root_parent(plugs, pm->plugname); assert(root_plugname); int is_active = plugname_active(root_plugname, pm->cmd); /* if not active, that means no active attempts to on/off/stat * the root plugname, so we need to stat it now */ if (!is_active) { struct powermsg *rootpm; /* no_output, we do not output this query result since it * is only to determine if we should perform power op */ rootpm = stat_cmd_plug(mh, root_plugname, NO_OUTPUT); if (!rootpm) goto next; powermsg_init_curl(rootpm); if (!(rootpm->handle = zlistx_add_end(activecmds, rootpm))) err_exit(true, "zlistx_add_end"); if (verbose > 1) fprintf(stderr, "DEBUG: parent query hostname=%s plugname=%s\n", rootpm->hostname, rootpm->plugname); } next: pm = zlistx_next(waitcmds); } } static void stat_cmd(CURLM *mh, char **av) { hostlist_iterator_t itr; char *plugname; hostlist_t *plugsptr; hostlist_t lplugs = NULL; if (av[0]) { if (!(lplugs = hostlist_create(av[0]))) { printf("illegal hosts input\n"); return; } plugsptr = &lplugs; } else plugsptr = plugs_hostlist(plugs); if (!(itr = hostlist_iterator_create(*plugsptr))) err_exit(true, "hostlist_iterator_create"); while ((plugname = hostlist_next(itr))) { struct powermsg *pm; if (!plugs_name_valid(plugs, plugname)) { printf("unknown plug specified: %s\n", plugname); free(plugname); continue; } if (!(pm = stat_cmd_plug(mh, plugname, OUTPUT_RESULT))) { free(plugname); continue; } if (pm->parent) { if (!(pm->handle = zlistx_add_end(waitcmds, pm))) err_exit(true, "zlistx_add_end"); } else { powermsg_init_curl(pm); if (!(pm->handle = zlistx_add_end(activecmds, pm))) err_exit(true, "zlistx_add_end"); } free(plugname); } if (zlistx_size(waitcmds) > 0) send_initial_parent_queries(mh); hostlist_iterator_destroy(itr); hostlist_destroy(lplugs); } /* status_strp - on, off, unknown * rstatus_strp - on, off, paused, poweringoff, poweringon, unknown */ static void parse_onoff_response(struct powermsg *pm, const char **status_strp, const char **rstatus_strp) { if (pm->output) { json_error_t error; json_t *o; if (!(o = json_loads(pm->output, 0, &error))) { (*status_strp) = "parse error"; if (rstatus_strp) (*rstatus_strp) = "parse error"; if (verbose) printf("%s: parse response error %s\n", pm->plugname, error.text); } else { json_t *val = json_object_get(o, "PowerState"); if (!val) { (*status_strp) = "no powerstate"; if (verbose) printf("%s: no PowerState\n", pm->plugname); } else { const char *str = json_string_value(val); if (strcasecmp(str, "On") == 0) { (*status_strp) = STATUS_ON; if (rstatus_strp) (*rstatus_strp) = STATUS_ON; } else if (strcasecmp(str, "Off") == 0) { (*status_strp) = STATUS_OFF; if (rstatus_strp) (*rstatus_strp) = STATUS_OFF; } else { (*status_strp) = STATUS_UNKNOWN; if (rstatus_strp) { if (strcasecmp(str, "Paused") == 0) (*rstatus_strp) = STATUS_PAUSED; else if (strcasecmp(str, "PoweringOff") == 0) (*rstatus_strp) = STATUS_POWERING_OFF; else if (strcasecmp(str, "PoweringOn") == 0) (*rstatus_strp) = STATUS_POWERING_ON; else (*rstatus_strp) = STATUS_UNKNOWN; } if (verbose) printf("%s: unknown status - %s\n", pm->plugname, str); } } } json_decref(o); } else (*status_strp) = "no output error"; } static void parse_onoff(struct powermsg *pm, const char **status_strp, const char **rstatus_strp) { if (!test_mode) { parse_onoff_response(pm, status_strp, rstatus_strp); return; } else { char *tmp = zhashx_lookup(test_power_status, pm->plugname); if (!tmp) err_exit(false, "zhashx_lookup on test status failed"); (*status_strp) = tmp; if (rstatus_strp) (*rstatus_strp) = tmp; } } static void process_waiters(CURLM *mh, const char *ancestor, const char *status_str) { struct powermsg *pm; /* first pass - deal with descendants that will be removed from * waitcmds (either removed outright or moved to activecmds) */ pm = zlistx_first(waitcmds); while (pm) { int descendant = plugs_is_descendant(plugs, pm->plugname, ancestor); if (descendant) { if (strcmp(status_str, STATUS_ON) != 0) { if (verbose > 1) fprintf(stderr, "DEBUG: descendant: " "%s hostname=%s plugname=%s status=%s\n", pm->cmd, pm->hostname, pm->plugname, status_str); if (pm->output_result) { /* for stat if ancestor is off/unknown/error, the child is * defined as off/unknown/error * * for off, if ancestor is off, we consider * operation a success * * otherwise can't do operation */ if (strcmp(pm->cmd, CMD_STAT) == 0) printf("%s: %s\n", pm->plugname, status_str); else if (strcmp(pm->cmd, CMD_OFF) == 0 && strcmp(status_str, STATUS_OFF) == 0) printf("%s: %s\n", pm->plugname, "ok"); else { struct plug_data *pd = plugs_get_data(plugs, ancestor); printf("%s: cannot perform %s, dependency %s" " (host=%s plug=%s)\n", pm->plugname, pm->cmd, status_str, pd->hostname, pd->plugname); } } /* this power op is now done */ zlistx_detach_cur(waitcmds); powermsg_destroy(pm); } else { /* if ancestor is direct parent, move waiter to active list */ if (strcmp(pm->parent, ancestor) == 0) { if (verbose > 1) fprintf(stderr, "DEBUG: %s hostname=%s plugname=%s " "moved to activecmds\n", pm->cmd, pm->hostname, pm->plugname); zlistx_detach_cur(waitcmds); powermsg_init_curl(pm); if (!(pm->handle = zlistx_add_end(activecmds, pm))) err_exit(true, "zlistx_add_end"); } } } pm = zlistx_next(waitcmds); } /* second loop only deals w/ STATUS_ON, so we can give up now if * not on */ if (strcmp(status_str, STATUS_ON) != 0) return; /* second pass - remaining descendants on waitcmds do not have * direct parent == ancestor, so we have to status query * the child of that ancestor. * * This has to be done as a second pass because we need to * previous loop to finish moving all possible power ops on * waitcmds to the activecmds list before we scan it with * plugname_active(). */ pm = zlistx_first(waitcmds); while (pm) { int descendant = plugs_is_descendant(plugs, pm->plugname, ancestor); if (descendant) { /* status query the child of that ancestor */ char *child = plugs_child_of_ancestor(plugs, pm->plugname, ancestor); assert(child); int is_active = plugname_active(child, pm->cmd); /* if not active, that means no active attempts to on/off/stat * the child plugname, so we need to stat it now */ if (!is_active) { struct powermsg *childpm; /* no_output, we do not output this query result since it * is only to determine if we should perform power op */ childpm = stat_cmd_plug(mh, child, NO_OUTPUT); if (!childpm) goto next; powermsg_init_curl(childpm); if (!(childpm->handle = zlistx_add_end(activecmds, childpm))) err_exit(true, "zlistx_add_end"); if (verbose > 1) fprintf(stderr, "DEBUG: parent query hostname=%s plugname=%s\n", childpm->hostname, childpm->plugname); } } next: pm = zlistx_next(waitcmds); } } static void stat_process(struct powermsg *pm) { const char *status_str; parse_onoff(pm, &status_str, NULL); if (pm->output_result) printf("%s: %s\n", pm->plugname, status_str); if (verbose > 1) fprintf(stderr, "DEBUG: %s hostname=%s plugname=%s status=%s\n", pm->cmd, pm->hostname, pm->plugname, status_str); process_waiters(pm->mh, pm->plugname, status_str); } static void stat_cleanup(struct powermsg *pm) { powermsg_destroy(pm); } struct powermsg *power_cmd_plug(CURLM * mh, char *plugname, const char *cmd) { struct powermsg *pm; struct plug_data *pd; char *path = NULL; char *postdata = NULL; if (!(pd = plugs_get_data(plugs, plugname))) { printf("plug not mapped: %s\n", plugname); return NULL; } get_path(cmd, plugname, &path, &postdata); if (!path) { printf("%s: %s path not set\n", plugname, cmd); return NULL; } pm = powermsg_create(mh, pd->hostname, plugname, pd->parent, cmd, path, postdata, NULL, 0, 0, OUTPUT_RESULT, STATE_SEND_POWERCMD); if (verbose > 1) printf("DEBUG: %s hostname=%s plugname=%s path=%s\n", cmd, pd->hostname, plugname, path); free(path); free(postdata); return pm; } /* We do not allow "phased" power on, where we power on a * parent, wait for it to finish, then power on a child. * * It ultimately proved too difficult to be done consistently well. * In many cases, you cannot power on a child after a parent. There * must be a delay as the parent "sets itself up". The delay can be * unknown. Testing on some hardware has shown itself to last * multiple minutes. * * Hypothetically, we could try powering on a child multiple times * until we succeed or some global timeout is reached. However, this * proves difficult, as there are varying degrees of errors that are * returned from that power on and it is difficult to ascertain which * errors are "good" vs "bad". e.g. is a connection timeout permanent * b/c a child is missing? or is a connection timeout temporary? * * So we simply don't allow it. Powering on different levels * is left to users. */ static void phased_power_on_check(const char *cmd) { struct powermsg **allpm; struct powermsg *pm; int total = 0; int i = 0; int cancel = 0; if (strcmp(cmd, CMD_ON) != 0) return; total += zlistx_size(activecmds); total += zlistx_size(waitcmds); assert(total > 0); /* single target can't be an ancestor of anyone else */ if (total == 1) return; /* we need to compare every target to every other target, an array * is easier for this than the lists. */ allpm = (struct powermsg **)xmalloc(sizeof(*allpm) * total); pm = zlistx_first(activecmds); while (pm) { allpm[i++] = pm; pm = zlistx_next(activecmds); } pm = zlistx_first(waitcmds); while (pm) { allpm[i++] = pm; pm = zlistx_next(waitcmds); } for (i = 0; i < (total - 1); i++) { struct powermsg *pm1 = allpm[i]; for (int j = i + 1; j < total; j++) { struct powermsg *pm2 = allpm[j]; int d1 = plugs_is_descendant(plugs, pm1->plugname, pm2->plugname); int d2 = plugs_is_descendant(plugs, pm2->plugname, pm1->plugname); if (d1 || d2) { cancel++; break; } } } if (cancel) { pm = zlistx_first(activecmds); while (pm) { printf("%s: %s\n", pm->plugname, "cannot turn on parent and child"); pm = zlistx_next(activecmds); } zlistx_purge(activecmds); pm = zlistx_first(waitcmds); while (pm) { printf("%s: %s\n", pm->plugname, "cannot turn on parent and child"); pm = zlistx_next(waitcmds); } zlistx_purge(waitcmds); } free(allpm); return; } static void power_cmd(CURLM *mh, char **av, const char *cmd) { hostlist_iterator_t itr; char *plugname; hostlist_t *plugsptr; hostlist_t lplugs = NULL; if (av[0]) { if (!(lplugs = hostlist_create(av[0]))) { printf("illegal hosts input\n"); return; } plugsptr = &lplugs; } else plugsptr = plugs_hostlist(plugs); if (!(itr = hostlist_iterator_create(*plugsptr))) err_exit(true, "hostlist_iterator_create"); while ((plugname = hostlist_next(itr))) { struct powermsg *pm; if (!plugs_name_valid(plugs, plugname)) { printf("unknown plug specified: %s\n", plugname); free(plugname); continue; } if (!(pm = power_cmd_plug(mh, plugname, cmd))) { free(plugname); continue; } if (pm->parent) { if (!(pm->handle = zlistx_add_end(waitcmds, pm))) err_exit(true, "zlistx_add_end"); } else { powermsg_init_curl(pm); if (!(pm->handle = zlistx_add_end(activecmds, pm))) err_exit(true, "zlistx_add_end"); } free(plugname); } /* if there are queries waiting for a parent check first, handle * here */ if (zlistx_size(waitcmds) > 0) { phased_power_on_check(cmd); send_initial_parent_queries(mh); } hostlist_iterator_destroy(itr); hostlist_destroy(lplugs); } static void on_cmd(CURLM *mh, char **av) { power_cmd(mh, av, CMD_ON); } static void off_cmd(CURLM *mh, char **av) { power_cmd(mh, av, CMD_OFF); } static void send_status_poll(struct powermsg *pm) { struct powermsg *nextpm; char *path = NULL; long int poll_delay; get_path(CMD_STAT, pm->plugname, &path, NULL); if (!path) { printf("%s: %s path not set\n", pm->plugname, CMD_STAT); return; } /* testing a range of hardware shows that the amount of time it * takes to complete an on/off falls into two bands. Either it * completes in the 2-8 second range OR it takes 20-60 seconds. * * Some example timings from a HPE Cray Supercomputing EX Chassis * * - Turn switch off - 1.18 seconds * - Turn switch on - 4.5 seconds * - Turn blade off - 1.18 seconds * - Turn blade on - 3.76 seconds * - Turn node off - 6.86 seconds * - Turn node on - 54.53 seconds * * (achu: Going off memory, the Supermicro H12DSG-O-CPU took * around 20 seconds for on/off.) * * To get the best turn around time for the quick end of that range * and avoid excessive polling on the other end, we will do a slightly * altered 'exponential backoff' delay. * * We delay 1 second each of the first 4 polls. * We delay 2 seconds for the 5th and 6th poll. * We delay 4 seconds afterwards. * * Special note, testing shows that powering on a "on" node can * also lead to a temporary entrance into the "PoweringOn" state. * So we also want a quick turnaround for that case, which is * typically only 1-2 seconds. */ if (pm->poll_count < 4) poll_delay = status_polling_interval; else if (pm->poll_count < 6) poll_delay = status_polling_interval * 2; else poll_delay = status_polling_interval * 4; /* issue a follow on stat to wait until the on/off is complete. * note that we set the initial start time of this new command to * the original on/off, so we can timeout correctly * * in addition, the cmd is the original on/off, indicating the true * purpose of this status query */ nextpm = powermsg_create(pm->mh, pm->hostname, pm->plugname, pm->parent, pm->cmd, path, NULL, &pm->start, poll_delay, pm->poll_count + 1, OUTPUT_RESULT, STATE_WAIT_UNTIL_ON_OFF); if (!(nextpm->handle = zlistx_add_end(delayedcmds, nextpm))) err_exit(true, "zlistx_add_end"); free(path); } static void on_off_process(struct powermsg *pm) { if (pm->state == STATE_SEND_POWERCMD) { /* just sent on or off, now we need for the operation to * complete */ send_status_poll(pm); /* in test mode, we simulate that the operation has already * finished */ if (test_mode) { if (strcmp(pm->cmd, CMD_ON) == 0) zhashx_update(test_power_status, pm->plugname, STATUS_ON); else { /* cmd == CMD_OFF */ zlistx_t *keys; char *name; zhashx_update(test_power_status, pm->plugname, STATUS_OFF); /* all children automatically become off too */ if (!(keys = zhashx_keys(test_power_status))) err_exit(false, "zhashx_keys"); name = zlistx_first(keys); while (name) { int descendant = plugs_is_descendant(plugs, name, pm->plugname); if (descendant) zhashx_update(test_power_status, name, STATUS_OFF); name = zlistx_next(keys); } zlistx_destroy(&keys); } } } else if (pm->state == STATE_WAIT_UNTIL_ON_OFF) { const char *status_str; const char *rstatus_str; struct timeval now; parse_onoff(pm, &status_str, &rstatus_str); if (strcmp(status_str, pm->cmd) == 0) { printf("%s: %s\n", pm->plugname, "ok"); process_waiters(pm->mh, pm->plugname, status_str); return; } /* check if we've timed out */ gettimeofday(&now, NULL); if (timercmp(&now, &pm->timeout, >)) { /* if target is not what it should be, this is unexpected, likely * hardware problem */ if ((strcmp(pm->cmd, CMD_ON) == 0 && strcmp(status_str, STATUS_OFF) == 0) || (strcmp(pm->cmd, CMD_OFF) == 0 && strcmp(status_str, STATUS_ON) == 0)) printf("%s: timeout - unexpected %s\n", pm->plugname, status_str); /* if still powering on/off, this is the "normal" timeout * scenario, timeout should be increased */ else if ((strcmp(pm->cmd, CMD_ON) == 0 && strcmp(rstatus_str, STATUS_POWERING_ON) == 0) || (strcmp(pm->cmd, CMD_OFF) == 0 && strcmp(rstatus_str, STATUS_POWERING_OFF) == 0)) printf("%s: timeout - %s still in progress\n", pm->plugname, pm->cmd); else { if (verbose) printf("%s: timeout - unknown status %s\n", pm->plugname, rstatus_str); else printf("%s: timeout\n", pm->plugname); } process_waiters(pm->mh, pm->plugname, STATUS_ERROR); return; } /* resend status poll */ send_status_poll(pm); } } static void on_process(struct powermsg *pm) { on_off_process(pm); } static void off_process(struct powermsg *pm) { on_off_process(pm); } static void power_cmd_process(struct powermsg *pm) { if (strcmp(pm->cmd, CMD_STAT) == 0) stat_process(pm); else if (strcmp(pm->cmd, CMD_ON) == 0) on_process(pm); else if (strcmp(pm->cmd, CMD_OFF) == 0) off_process(pm); } static void power_cleanup(struct powermsg *pm) { if (!test_mode && pm->eh) { Curl_easy_setopt((pm->eh, CURLOPT_POSTFIELDS, "")); Curl_easy_setopt((pm->eh, CURLOPT_POSTFIELDSIZE, 0)); } powermsg_destroy(pm); } static void on_cleanup(struct powermsg *pm) { power_cleanup(pm); } static void off_cleanup(struct powermsg *pm) { power_cleanup(pm); } static void auth(char **av) { if (av[0] == NULL) { printf("Usage: auth user:passwd\n"); return; } if (userpwd_set_on_cmdline) return; if (userpwd) xfree(userpwd); userpwd = xstrdup(av[0]); } static void setheader(char **av) { if (header) { xfree(header); if (!test_mode) curl_slist_free_all(header_list); header = NULL; header_list = NULL; } if (av[0]) { header = xstrdup(av[0]); if (!test_mode) header_list = curl_slist_append(header_list, header); } } static void setstatpath(char **av) { if (statpath) { xfree(statpath); statpath = NULL; } if (av[0]) statpath = xstrdup(av[0]); } static void setpowerpath(char **av, char **path, char **postdata) { if (*path) { xfree(*path); *path = NULL; } if (*postdata) { xfree(*postdata); *postdata = NULL; } if (av[0]) { (*path) = xstrdup(av[0]); if (av[1]) (*postdata) = xstrdup(av[1]); } } static void remove_initial_plugs(void) { hostlist_iterator_t itr; char *hostname; if (!initial_plugs_setup) return; if (!(itr = hostlist_iterator_create(hosts))) err_exit(true, "hostlist_iterator_create"); while ((hostname = hostlist_next(itr))) { plugs_remove(plugs, hostname); free(hostname); } hostlist_iterator_destroy(itr); initial_plugs_setup = 0; return; } static int setup_plug(const char *plugname, const char *hostindexstr, const char *parent) { char *host; char *endptr; int hostindex; errno = 0; hostindex = strtol(hostindexstr, &endptr, 10); if (errno || endptr[0] != '\0' || hostindex < 0) { printf("setplugs: invalid hostindex %s specified\n", hostindexstr); return -1; } if (!(host = hostlist_nth(hosts, hostindex))) { printf("setplugs: hostindex %d out of range\n", hostindex); return -1; } plugs_add(plugs, plugname, host, parent); /* initialize plug to "off" for testing */ if (test_mode) zhashx_insert(test_power_status, plugname, STATUS_OFF); free(host); return 0; } static void setplugs(char **av) { hostlist_t lplugs = NULL; hostlist_t hostindices = NULL; int plugcount, hostindexcount; char *plug; char *hostindexstr; int i; if (!av[0] || !av[1]) { printf("Usage: setplugs []]\n"); return; } if (!(lplugs = hostlist_create(av[0]))) { printf("setplugs: illegal plugnames input\n"); goto cleanup; } if (!(hostindices = hostlist_create(av[1]))) { printf("setplugs: illegal hostindices input\n"); goto cleanup; } plugcount = hostlist_count(lplugs); hostindexcount = hostlist_count(hostindices); /* if user is electing to configure their own plugs, we must remove * all of the initial ones configured in setup_hosts() */ remove_initial_plugs(); if (plugcount != hostindexcount) { /* special case, user will use plug substitution */ if (plugcount > 1 && hostindexcount == 1) { if (!(hostindexstr = hostlist_nth(hostindices, 0))) err_exit(false, "setplugs: hostlist_nth contains no indices"); for (i = 0; i < plugcount; i++) { if (!(plug = hostlist_nth(lplugs, i))) err_exit(false, "setplugs: hostlist_nth plugs"); if (setup_plug(plug, hostindexstr, av[2]) < 0) { free(plug); free(hostindexstr); goto cleanup; } free(plug); } free(hostindexstr); } else { printf("setplugs: plugs count not equal to host index count\n"); goto cleanup; } } else { for (i = 0; i < plugcount; i++) { if (!(plug = hostlist_nth(lplugs, i))) err_exit(false, "setplugs: hostlist_nth plugs"); if (!(hostindexstr = hostlist_nth(hostindices, i))) err_exit(false, "setplugs: hostlist_nth indices"); if (setup_plug(plug, hostindexstr, av[2]) < 0) { free(plug); free(hostindexstr); goto cleanup; } free(plug); free(hostindexstr); } } cleanup: hostlist_destroy(lplugs); hostlist_destroy(hostindices); } static void setpath(char **av) { hostlist_t lplugs = NULL; hostlist_iterator_t itr = NULL; char *plugname; if (!av[0] || !av[1] || !av[2]) { printf("Usage: setpath []\n"); return; } if (strcmp(av[1], CMD_STAT) != 0 && strcmp(av[1], CMD_ON) != 0 && strcmp(av[1], CMD_OFF) != 0) { printf("setpath: invalid command specified\n"); return; } if (!(lplugs = hostlist_create(av[0]))) { printf("setpath: illegal hosts input\n"); return; } itr = hostlist_iterator_create(lplugs); while ((plugname = hostlist_next(itr))) { if (!plugs_name_valid(plugs, plugname)) { printf("setpath: unknown plug specified: %s\n", plugname); free(plugname); goto cleanup; } if (plugs_update_path(plugs, plugname, av[1], av[2], av[3]) < 0) err_exit(false, "setpath: plugs_update_path failed"); free(plugname); } cleanup: hostlist_iterator_destroy(itr); hostlist_destroy(lplugs); } static void settimeout(char **av) { if (av[0]) { char *endptr; long tmp; errno = 0; tmp = strtol(av[0], &endptr, 10); if (errno || endptr[0] != '\0' || tmp <= 0) printf("invalid timeout specified\n"); cmd_timeout = tmp; } } static void process_cmd(CURLM *mh, char **av, int *exitflag) { if (av[0] != NULL) { if (strcmp(av[0], "help") == 0) help(); else if (strcmp(av[0], "quit") == 0) (*exitflag) = 1; else if (strcmp(av[0], "auth") == 0) auth(av + 1); else if (strcmp(av[0], "setheader") == 0) setheader(av + 1); else if (strcmp(av[0], "setstatpath") == 0) setstatpath(av + 1); else if (strcmp(av[0], "setonpath") == 0) setpowerpath(av + 1, &onpath, &onpostdata); else if (strcmp(av[0], "setoffpath") == 0) setpowerpath(av + 1, &offpath, &offpostdata); else if (strcmp(av[0], "setplugs") == 0) setplugs(av + 1); else if (strcmp(av[0], "setpath") == 0) setpath(av + 1); else if (strcmp(av[0], "settimeout") == 0) settimeout(av + 1); else if (strcmp(av[0], CMD_STAT) == 0) stat_cmd(mh, av + 1); else if (strcmp(av[0], CMD_ON) == 0) on_cmd(mh, av + 1); else if (strcmp(av[0], CMD_OFF) == 0) off_cmd(mh, av + 1); else printf("type \"help\" for a list of commands\n"); } } static void cleanup_powermsg(void **x) { struct powermsg *pm = *x; if (pm) { if (strcmp(pm->cmd, CMD_STAT) == 0) stat_cleanup(pm); else if (strcmp(pm->cmd, CMD_ON) == 0) on_cleanup(pm); else if (strcmp(pm->cmd, CMD_OFF) == 0) off_cleanup(pm); } } static void output_curl_error(struct CURLMsg *cmsg, struct powermsg *pm) { if (cmsg->data.result == CURLE_HTTP_RETURNED_ERROR) { /* N.B. curl returns this error code for all response * codes >= 400. So gotta dig in more. */ long code; if (curl_easy_getinfo(cmsg->easy_handle, CURLINFO_RESPONSE_CODE, &code) != CURLE_OK) printf("%s: %s\n", pm->plugname, "http error"); if (code == 400) printf("%s: %s\n", pm->plugname, "bad request"); else if (code == 401) printf("%s: %s\n", pm->plugname, "unauthorized"); else if (code == 404) printf("%s: %s\n", pm->plugname, "not found"); else printf("%s: %s (%ld)\n", pm->plugname, "http error", code); } else printf("%s: %s\n", pm->plugname, curl_easy_strerror(cmsg->data.result)); if (verbose) printf("%s: %s\n", pm->plugname, curl_easy_strerror(cmsg->data.result)); } static void shell(CURLM *mh) { int exitflag = 0; while (exitflag == 0) { CURLMcode mc; fd_set fdread; fd_set fdwrite; fd_set fderror; struct timeval timeout = {0}; struct timeval *timeoutptr = NULL; int maxfd = -1; FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fderror); if (!zlistx_size(activecmds) && !zlistx_size(delayedcmds) && !zlistx_size(waitcmds)) { printf("redfishpower> "); fflush(stdout); FD_SET(STDIN_FILENO, &fdread); timeoutptr = NULL; maxfd = STDIN_FILENO; } else { struct timeval curl_timeout; long curl_timeout_ms; /* First check if there are any delayedcmds to send or are * waiting. If there are some ready to send, put to * activecmds. If not, setup timeout accordingly if one * is waiting */ if (zlistx_size(delayedcmds) > 0) { struct powermsg *delaypm = zlistx_first(delayedcmds); struct timeval delaytimeout; struct timeval now; gettimeofday(&now, NULL); while (delaypm) { if (timercmp(&delaypm->delaystart, &now, >)) break; zlistx_detach_cur(delayedcmds); powermsg_init_curl(delaypm); if (!(delaypm->handle = zlistx_add_end(activecmds, delaypm))) err_exit(true, "zlistx_add_end"); delaypm = zlistx_next(delayedcmds); } delaypm = zlistx_first(delayedcmds); if (delaypm) { timersub(&delaypm->delaystart, &now, &delaytimeout); timeout.tv_sec = delaytimeout.tv_sec; timeout.tv_usec = delaytimeout.tv_usec; timeoutptr = &timeout; } } if (!test_mode) { if ((mc = curl_multi_timeout(mh, &curl_timeout_ms)) != CURLM_OK) err_exit(false, "curl_multi_timeout: %s", curl_multi_strerror(mc)); /* Per documentation, wait incremental time then * proceed if timeout < 0 */ if (curl_timeout_ms < 0) curl_timeout_ms = INCREMENTAL_WAIT; curl_timeout.tv_sec = curl_timeout_ms / MS_IN_SEC; curl_timeout.tv_usec = (curl_timeout_ms % MS_IN_SEC) * MS_IN_SEC; /* if timeout previously set, must compare */ if (timeoutptr) { /* only compare if curl_timeout_ms > 0, otherwise * we'd spin */ if (curl_timeout_ms > 0) { if (timercmp(&curl_timeout, timeoutptr, <)) { timeoutptr->tv_sec = curl_timeout.tv_sec; timeoutptr->tv_usec = curl_timeout.tv_usec; } } } else { timeout.tv_sec = curl_timeout.tv_sec; timeout.tv_usec = curl_timeout.tv_usec; timeoutptr = &timeout; } if ((mc = curl_multi_fdset(mh, &fdread, &fdwrite, &fderror, &maxfd)) != CURLM_OK) err_exit(false, "curl_multi_fdset: %s", curl_multi_strerror(mc)); } else { /* in test-mode assume active cmds complete * "immediately" by setting timeout to 0 * * otherwise wait delayedcmds timeout or wait forever * (timeoutptr initialized to NULL) */ if (zlistx_size(activecmds) > 0) { timeout.tv_sec = 0; timeout.tv_usec = 0; timeoutptr = &timeout; } } } /* XXX: use curl_multi_poll/wait on newer versions of curl */ if (select(maxfd+1, &fdread, &fdwrite, &fderror, timeoutptr) < 0) err_exit(true, "select"); if (FD_ISSET(STDIN_FILENO, &fdread)) { char buf[256]; if (fgets(buf, sizeof(buf), stdin)) { char **av; av = argv_create(buf, ""); process_cmd(mh, av, &exitflag); argv_destroy(av); } else break; if (exitflag) break; } if (zlistx_size(activecmds) == 0) continue; if (!test_mode) { struct CURLMsg *cmsg; int msgq = 0; int stillrunning; if ((mc = curl_multi_perform(mh, &stillrunning)) != CURLM_OK) err_exit(false, "curl_multi_perform: %s", curl_multi_strerror(mc)); do { cmsg = curl_multi_info_read(mh, &msgq); if(cmsg && (cmsg->msg == CURLMSG_DONE)) { struct powermsg *pm = NULL; CURL *eh = cmsg->easy_handle; CURLcode ec; if ((ec = curl_easy_getinfo(eh, CURLINFO_PRIVATE, (char **)&pm)) != CURLE_OK) err_exit(false, "curl_easy_getinfo: %s", curl_easy_strerror(ec)); if (!pm) err_exit(false, "private data not set in easy handle"); if (cmsg->data.result != 0) { if (pm->output_result) output_curl_error (cmsg, pm); process_waiters(mh, pm->plugname, STATUS_ERROR); } else power_cmd_process(pm); fflush(stdout); if (zlistx_delete(activecmds, pm->handle) < 0) err_exit(false, "zlistx_delete failed to delete"); } } while (cmsg); } else { /* in test mode we assume all activecmds complete immediately */ /* process_waiters() can traverse and append to the * activecmds list (it can also be called within * power_cmd_process()), thus disrupt the zlistx cursor. * * Copy all current activecmds into a new list and delete * them from activecmds at the end. */ zlistx_t *cpy = zlistx_new(); struct powermsg *pm; if (!cpy) err_exit(true, "zlistx_new"); pm = zlistx_first(activecmds); while (pm) { /* do not save handle, we want handle for activecmds list */ if (!zlistx_add_end(cpy, pm)) err_exit(true, "zlistx_add_end"); pm = zlistx_next(activecmds); } pm = zlistx_first(cpy); while (pm) { if (hostlist_find(test_fail_power_cmd_hosts, pm->hostname) >= 0) { if (pm->output_result) printf("%s: %s\n", pm->plugname, "error"); process_waiters(mh, pm->plugname, STATUS_ERROR); } else power_cmd_process(pm); fflush(stdout); pm = zlistx_next(cpy); } pm = zlistx_first(cpy); while (pm) { if (zlistx_delete(activecmds, pm->handle) < 0) err_exit(false, "zlistx_delete failed to delete"); pm = zlistx_next(cpy); } zlistx_destroy(&cpy); } } } static void usage(void) { fprintf(stderr, "Usage: redfishpower --hostname host(s) [OPTIONS]\n" " OPTIONS:\n" " -H, --header Set extra header string\n" " -S, --statpath Set stat path\n" " -O, --onpath Set on path\n" " -F, --offpath Set off path\n" " -P, --onpostdata Set on post data\n" " -G, --offpostdata Set off post data\n" " -m, --message-timeout Set message timeout\n" " -o, --resolve-hosts Resolve host to IP before passing to libcurl\n" " -v, --verbose Increase output verbosity\n" ); exit(1); } static void free_wrapper(void **item) { if (item) { free(*item); *item = NULL; } } static void init_redfishpower(char *argv[]) { err_init(basename(argv[0])); if (!(hosts = hostlist_create(NULL))) err_exit(true, "hostlist_create error"); if (!(activecmds = zlistx_new())) err_exit(true, "zlistx_new"); zlistx_set_destructor(activecmds, cleanup_powermsg); if (!(delayedcmds = zlistx_new())) err_exit(true, "zlistx_new"); zlistx_set_destructor(delayedcmds, cleanup_powermsg); if (!(waitcmds = zlistx_new())) err_exit(true, "zlistx_new"); zlistx_set_destructor(waitcmds, cleanup_powermsg); if (!(test_fail_power_cmd_hosts = hostlist_create(NULL))) err_exit(true, "hostlist_create error"); if (!(test_power_status = zhashx_new ())) err_exit(false, "zhashx_new error"); if (!(plugs = plugs_create())) err_exit(true, "plugs_create"); if (!(resolve_hosts_cache = zhashx_new ())) err_exit(false, "zhashx_new error"); zhashx_set_destructor(resolve_hosts_cache, free_wrapper); } static void cleanup_redfishpower(void) { xfree(userpwd); xfree(statpath); xfree(onpath); xfree(onpostdata); xfree(offpath); xfree(offpostdata); hostlist_destroy(hosts); zlistx_destroy(&activecmds); zlistx_destroy(&delayedcmds); zlistx_destroy(&waitcmds); hostlist_destroy(test_fail_power_cmd_hosts); zhashx_destroy(&test_power_status); plugs_destroy(plugs); zhashx_destroy(&resolve_hosts_cache); } static void setup_hosts(void) { hostlist_iterator_t itr; char *hostname; if (!(itr = hostlist_iterator_create(hosts))) err_exit(true, "hostlist_iterator_create"); /* initially all hosts on the command line are made the plugnames */ while ((hostname = hostlist_next(itr))) { plugs_add(plugs, hostname, hostname, NULL); free(hostname); } hostlist_iterator_destroy(itr); initial_plugs_setup = 1; } /* From David Wheeler's Secure Programming Guide * - do not want compiler to optimize away memset() */ static void *secure_memset(void *s, int c, size_t n) { volatile char *p; if (!s || !n) return (NULL); p = s; while (n--) *p++=c; return (s); } int main(int argc, char *argv[]) { CURLM *mh = NULL; CURLcode ec; int c; char *endptr; init_redfishpower(argv); while ((c = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != EOF) { switch (c) { case 'h': /* --hostname */ if (!hostlist_push(hosts, optarg)) err_exit(true, "hostlist_push error on %s", optarg); break; case 'H': /* --header */ header = xstrdup(optarg); break; case 'A': /* -- auth */ userpwd = xstrdup(optarg); userpwd_set_on_cmdline = 1; secure_memset(optarg, '\0', strlen(optarg)); break; case 'S': /* --statpath */ statpath = xstrdup(optarg); break; case 'O': /* --onpath */ onpath = xstrdup(optarg); break; case 'F': /* --offpath */ offpath = xstrdup(optarg); break; case 'P': /* --onpostdata */ onpostdata = xstrdup(optarg); break; case 'G': /* --offpostdata */ offpostdata = xstrdup(optarg); break; case 'm': /* --message-timeout */ errno = 0; message_timeout = strtol(optarg, &endptr, 10); if (errno || endptr[0] != '\0' || message_timeout <= 0) err_exit(false, "invalid message timeout specified\n"); break; case 'o': /* --resolve_hosts */ resolve_hosts = 1; break; case 'T': /* --test-mode */ test_mode = 1; break; case 'E': /* --test-fail-power-cmd-hosts */ if (!hostlist_push(test_fail_power_cmd_hosts, optarg)) err_exit(true, "hostlist_push error on %s", optarg); break; case 'v': /* --verbose */ verbose++; break; default: usage(); break; } } if (optind < argc) usage(); if (hostlist_count(hosts) == 0) usage(); setup_hosts(); if (!test_mode) { if ((ec = curl_global_init(CURL_GLOBAL_ALL)) != CURLE_OK) err_exit(false, "curl_global_init: %s", curl_easy_strerror(ec)); if (!(mh = curl_multi_init())) err_exit(false, "curl_multi_init failed"); } else { /* All hosts initially are off for testing */ hostlist_t *lplugs = plugs_hostlist(plugs); hostlist_iterator_t itr; char *plugname; if (!(itr = hostlist_iterator_create(*lplugs))) err_exit(true, "hostlist_iterator_create"); while ((plugname = hostlist_next(itr))) { if (zhashx_insert(test_power_status, plugname, STATUS_OFF) < 0) err_exit(false, "zhashx_insert failure"); free(plugname); } hostlist_iterator_destroy(itr); /* under test mode we can make the polling interval a lot smaller * lets put it to a millisecond. */ status_polling_interval = 1000; /* output settings of command line options that can't be tested in test mode */ if (header) fprintf(stderr, "command line option: header = %s\n", header); if (userpwd) fprintf(stderr, "command line option: auth = %s\n", userpwd); if (message_timeout != MESSAGE_TIMEOUT_DEFAULT) fprintf(stderr, "command line option: message timeout = %ld\n", message_timeout); fprintf(stderr, "command line option: resolve-hosts = %s\n", resolve_hosts ? "set" : "not set"); } shell(mh); if (!test_mode) curl_multi_cleanup(mh); cleanup_redfishpower(); exit(0); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/redfishpower/redfishpower_defs.h000066400000000000000000000011601467035776500225360ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2024 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifndef REDFISHPOWER_DEFS_H #define REDFISHPOWER_DEFS_H #define CMD_STAT "stat" #define CMD_ON "on" #define CMD_OFF "off" #endif /* REDFISHPOWER_DEFS_H */ /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/src/redfishpower/test/000077500000000000000000000000001467035776500176445ustar00rootroot00000000000000powerman-2.4.4/src/redfishpower/test/plugs.c000066400000000000000000000235761467035776500211570ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2024 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* * Test driver for plugs */ #include #include #include #include "tap.h" #include "plugs.h" static void basic_tests(void) { plugs_t *p; struct plug_data *pd; hostlist_t *hl; int count; p = plugs_create(); if (!p) BAIL_OUT("plugs_create"); count = plugs_count(p); ok(count == 0, "plugs_count returns 0 plugs before we added any"); plugs_add(p, "blade0", "node0", NULL); plugs_add(p, "blade1", "node1", NULL); count = plugs_count(p); ok(count == 2, "plugs_count returns correct number of plugs"); ok(plugs_name_valid(p, "blade0") == 1, "plug blade0 is valid"); ok(plugs_name_valid(p, "blade1") == 1, "plug blade1 is valid"); ok(plugs_name_valid(p, "foof") == 0, "plug foof is not valid"); hl = plugs_hostlist(p); ok(hostlist_count(*hl) == 2, "hostlist contains 2 plugs"); ok(hostlist_find(*hl, "blade0") >= 0, "hostlist contains blade0"); ok(hostlist_find(*hl, "blade1") >= 0, "hostlist contains blade1"); pd = plugs_get_data(p, "blade0"); ok(pd != NULL, "plugs_get_data returns data for blade0"); pd = plugs_get_data(p, "blade0"); ok(strcmp(pd->plugname, "blade0") == 0 && strcmp(pd->hostname, "node0") == 0, "plugs_get_data returns correct plug"); pd = plugs_get_data(p, "foof"); ok(pd == NULL, "plugs_get_data returns NULL for invalid plug"); /* remove works */ plugs_remove(p, "blade1"); count = plugs_count(p); ok(count == 1, "plugs_count returns correct number of plugs after removal"); ok(plugs_name_valid(p, "blade0") == 1, "plug blade0 is valid"); ok(plugs_name_valid(p, "blade1") == 0, "plug blade1 is not valid"); /* overwrite works */ plugs_add(p, "blade0", "nodeX", NULL); ok(hostlist_count(*hl) == 1, "hostlist contains 1 plugs"); ok(plugs_name_valid(p, "blade0") == 1, "plug blade0 is valid"); pd = plugs_get_data(p, "blade0"); ok(strcmp(pd->hostname, "nodeX") == 0, "plugs_get_data returns correct overwrite host"); plugs_destroy(p); } static void path_tests(void) { plugs_t *p; struct plug_data *pd; int ret; p = plugs_create(); if (!p) BAIL_OUT("plugs_create"); plugs_add(p, "blade0", "node0", NULL); plugs_add(p, "blade1", "node1", NULL); ret = plugs_update_path(p, "blade0", "stat", "statpath0", NULL); ok(ret == 0, "plugs_update_path of stat path works on blade0"); ret = plugs_update_path(p, "blade0", "on", "onpath0", "onpostdata0"); ok(ret == 0, "plugs_update_path of on path works on blade0"); /* intionally leave no postdata for off for testing */ ret = plugs_update_path(p, "blade0", "off", "offpath0", NULL); ok(ret == 0, "plugs_update_path of off path works on blade0"); ret = plugs_update_path(p, "blade1", "stat", "statpath1", NULL); ok(ret == 0, "plugs_update_path of stat path works on blade1"); ret = plugs_update_path(p, "blade1", "on", "onpath1", "onpostdata1"); ok(ret == 0, "plugs_update_path of on path works on blade1"); /* intionally leave no postdata for off for testing */ ret = plugs_update_path(p, "blade1", "off", "offpath1", NULL); ok(ret == 0, "plugs_update_path of off path works on blade1"); ret = plugs_update_path(p, "foof", "stat", "statpath", NULL); ok(ret == -1, "plugs_update_path of invalid plug fails"); ret = plugs_update_path(p, "blade0", "foof", "statpath", NULL); ok(ret == -1, "plugs_update_path of invalid cmd fails"); pd = plugs_get_data(p, "blade0"); ok(strcmp(pd->stat, "statpath0") == 0, "blade0 has correct stat path"); ok(strcmp(pd->on, "onpath0") == 0, "blade0 has correct on path"); ok(strcmp(pd->onpostdata, "onpostdata0") == 0, "blade0 has correct on postdata"); ok(strcmp(pd->off, "offpath0") == 0, "blade0 has correct off path"); ok(pd->offpostdata == NULL, "blade0 has no off postdata"); pd = plugs_get_data(p, "blade1"); ok(strcmp(pd->stat, "statpath1") == 0, "blade1 has correct stat path"); ok(strcmp(pd->on, "onpath1") == 0, "blade1 has correct on path"); ok(strcmp(pd->onpostdata, "onpostdata1") == 0, "blade1 has correct on postdata"); ok(strcmp(pd->off, "offpath1") == 0, "blade1 has correct off path"); ok(pd->offpostdata == NULL, "blade1 has no off postdata"); plugs_destroy(p); } static void hierarchy_tests(void) { plugs_t *p; struct plug_data *pd; char *plug; int ret; p = plugs_create(); if (!p) BAIL_OUT("plugs_create"); /* * simple 3 level binary tree with 7 nodes. * * note that for these tests the hostname is basically irrelevant */ plugs_add(p, "node0", "foo0", NULL); plugs_add(p, "node1", "foo1", "node0"); plugs_add(p, "node2", "foo2", "node0"); plugs_add(p, "node3", "foo3", "node1"); plugs_add(p, "node4", "foo4", "node1"); plugs_add(p, "node5", "foo5", "node2"); plugs_add(p, "node6", "foo6", "node2"); pd = plugs_get_data(p, "node0"); ok(pd->parent == NULL, "no parent for node0 configured"); pd = plugs_get_data(p, "node1"); ok(strcmp(pd->parent, "node0") == 0, "parent of node1 is node0"); pd = plugs_get_data(p, "node3"); ok(strcmp(pd->parent, "node1") == 0, "parent of node3 is node1"); /* plugs_find_root_parent tests */ plug = plugs_find_root_parent(p, "node0"); ok(strcmp(plug, "node0") == 0, "plugs_find_root_parent finds correct root for node0"); plug = plugs_find_root_parent(p, "node1"); ok(strcmp(plug, "node0") == 0, "plugs_find_root_parent finds correct root for node1"); plug = plugs_find_root_parent(p, "node2"); ok(strcmp(plug, "node0") == 0, "plugs_find_root_parent finds correct root for node2"); plug = plugs_find_root_parent(p, "node3"); ok(strcmp(plug, "node0") == 0, "plugs_find_root_parent finds correct root for node3"); plug = plugs_find_root_parent(p, "node4"); ok(strcmp(plug, "node0") == 0, "plugs_find_root_parent finds correct root for node4"); plug = plugs_find_root_parent(p, "node5"); ok(strcmp(plug, "node0") == 0, "plugs_find_root_parent finds correct root for node5"); plug = plugs_find_root_parent(p, "node6"); ok(strcmp(plug, "node0") == 0, "plugs_find_root_parent finds correct root for node6"); /* plugs_is_descendant tests */ ret = plugs_is_descendant(p, "node0", "node0"); ok(ret == 0, "plugs_is_descendant, node0 is not descendant of node0 "); ret = plugs_is_descendant(p, "node0", "node1"); ok(ret == 0, "plugs_is_descendant, node1 is not descendant of node0 "); ret = plugs_is_descendant(p, "node0", "node3"); ok(ret == 0, "plugs_is_descendant, node1 is not descendant of node0 "); ret = plugs_is_descendant(p, "node1", "node0"); ok(ret == 1, "plugs_is_descendant, node1 is descendant of node0 "); ret = plugs_is_descendant(p, "node3", "node0"); ok(ret == 1, "plugs_is_descendant, node3 is descendant of node0 "); ret = plugs_is_descendant(p, "node5", "node0"); ok(ret == 1, "plugs_is_descendant, node5 is descendant of node0 "); ret = plugs_is_descendant(p, "node2", "node1"); ok(ret == 0, "plugs_is_descendant, node2 is not descendant of node1 "); ret = plugs_is_descendant(p, "node3", "node1"); ok(ret == 1, "plugs_is_descendant, node3 is descendant of node1 "); ret = plugs_is_descendant(p, "node4", "node1"); ok(ret == 1, "plugs_is_descendant, node4 is descendant of node1 "); ret = plugs_is_descendant(p, "node5", "node1"); ok(ret == 0, "plugs_is_descendant, node5 is not descendant of node1 "); ret = plugs_is_descendant(p, "node2", "node3"); ok(ret == 0, "plugs_is_descendant, node2 is not descendant of node3 "); ret = plugs_is_descendant(p, "node3", "node3"); ok(ret == 0, "plugs_is_descendant, node3 is not descendant of node3 "); ret = plugs_is_descendant(p, "node5", "node3"); ok(ret == 0, "plugs_is_descendant, node5 is not descendant of node3 "); /* plugs_child_of_ancestor tests */ plug = plugs_child_of_ancestor(p, "node0", "node0"); ok(plug == NULL, "plugs_child_of_ancestor no child of node0 from node0"); plug = plugs_child_of_ancestor(p, "node1", "node1"); ok(plug == NULL, "plugs_child_of_ancestor no child of node1 from node1"); plug = plugs_child_of_ancestor(p, "node2", "node3"); ok(plug == NULL, "plugs_child_of_ancestor no child of node3 from node2"); plug = plugs_child_of_ancestor(p, "node1", "node0"); ok(strcmp(plug, "node1") == 0, "plugs_child_of_ancestor child of node0 starting from node1 is node1"); plug = plugs_child_of_ancestor(p, "node2", "node0"); ok(strcmp(plug, "node2") == 0, "plugs_child_of_ancestor child of node0 starting from node2 is node2"); plug = plugs_child_of_ancestor(p, "node3", "node0"); ok(strcmp(plug, "node1") == 0, "plugs_child_of_ancestor child of node0 starting from node3 is node1"); plug = plugs_child_of_ancestor(p, "node5", "node0"); ok(strcmp(plug, "node2") == 0, "plugs_child_of_ancestor child of node0 starting from node5 is node2"); plugs_destroy(p); } int main(int argc, char *argv[]) { plan(NO_PLAN); basic_tests(); path_tests(); hierarchy_tests(); done_testing(); } powerman-2.4.4/src/snmppower/000077500000000000000000000000001467035776500162165ustar00rootroot00000000000000powerman-2.4.4/src/snmppower/Makefile.am000066400000000000000000000003321467035776500202500ustar00rootroot00000000000000AM_CFLAGS = @WARNING_CFLAGS@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcommon sbin_PROGRAMS = snmppower snmppower_SOURCES = snmppower.c snmppower_LDADD = \ $(top_builddir)/src/libcommon/libcommon.la \ $(LIBNETSNMP) powerman-2.4.4/src/snmppower/snmppower.c000066400000000000000000000212521467035776500204160ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2010 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include "xmalloc.h" #include "error.h" #include "argv.h" #define OPTIONS "h:" static struct option longopts[] = { {"hostname", required_argument, 0, 'h' }, {0,0,0,0}, }; static void get (char **av, struct snmp_session **ssp) { struct snmp_pdu *pdu; struct snmp_pdu *response; oid anOID[MAX_OID_LEN]; size_t anOID_len = MAX_OID_LEN; struct variable_list *vars; int status; if (av[1] == NULL) { err (false, "missing oid"); return; } if (*ssp == NULL) { err (false, "start session first"); return; } pdu = snmp_pdu_create (SNMP_MSG_GET); if (!get_node (av[1], anOID, &anOID_len)) { snmp_free_pdu (pdu); printf ("error parsing oid\n"); return; } snmp_add_null_var (pdu, anOID, anOID_len); status = snmp_synch_response (*ssp, pdu, &response); if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) { for (vars = response->variables; vars; vars = vars->next_variable) { switch (vars->type) { case ASN_OCTET_STR: printf("%s: %*s\n", av[1], (int)vars->val_len, vars->val.string); break; case ASN_INTEGER: printf("%s: %ld\n", av[1], *vars->val.integer); break; default: print_variable (vars->name, vars->name_length, vars); break; } } } else { if (status == STAT_SUCCESS) err_exit (false, "error in packet: %s", snmp_errstring (response->errstat)); else snmp_sess_perror ("snmpget", *ssp); } if (response) snmp_free_pdu (response); } static void set (char **av, struct snmp_session **ssp) { struct snmp_pdu *pdu; struct snmp_pdu *response; oid anOID[MAX_OID_LEN]; size_t anOID_len = MAX_OID_LEN; struct variable_list *vars; int status; if (av[1] == NULL) { err (false, "missing oid"); return; } if (av[2] == NULL) { err (false, "missing type"); return; } if (av[3] == NULL) { err (false, "missing value"); return; } if (*ssp == NULL) { err (false, "start session first"); return; } pdu = snmp_pdu_create (SNMP_MSG_SET); if (!get_node (av[1], anOID, &anOID_len)) { snmp_free_pdu (pdu); printf ("error parsing oid\n"); return; } snmp_add_var (pdu, anOID, anOID_len, *(av[2]), av[3]); status = snmp_synch_response (*ssp, pdu, &response); if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) { for (vars = response->variables; vars; vars = vars->next_variable) { switch (vars->type) { case ASN_OCTET_STR: printf("%s: %*s\n", av[1], (int)vars->val_len, vars->val.string); break; case ASN_INTEGER: printf("%s: %ld\n", av[1], *vars->val.integer); break; default: print_variable (vars->name, vars->name_length, vars); break; } } } else { if (status == STAT_SUCCESS) err_exit (false, "error in packet: %s", snmp_errstring (response->errstat)); else snmp_sess_perror ("snmpset", *ssp); } if (response) snmp_free_pdu (response); } static void start_v1v2c (char **av, int version, char *hostname, struct snmp_session **ssp) { struct snmp_session session; if (av[1] == NULL) { err (false, "missing community"); return; } if (*ssp) { err (false, "finish current session first"); return; } snmp_sess_init (&session); session.version = version; session.community = (u_char *)xstrdup (av[1]); session.community_len = strlen (av[1]); session.peername = hostname; if (!(*ssp = snmp_open (&session))) { err (false, "snmp_open failed"); xfree (session.community); } } static void start_v3 (char **av, char *hostname, struct snmp_session **ssp) { struct snmp_session session; if (av[1] == NULL) { err (false, "missing security name"); return; } if (av[2] == NULL) { err (false, "missing passphrase"); return; } if (strlen (av[2]) < 8) { err (false, "passphrase must be at least 8 characters"); return; } snmp_sess_init (&session); session.version = SNMP_VERSION_3; session.peername = hostname; session.securityName = xstrdup (av[1]); session.securityNameLen = strlen (av[1]); session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV; session.securityAuthProto = usmHMACMD5AuthProtocol; session.securityAuthProtoLen = sizeof (usmHMACMD5AuthProtocol) / sizeof (oid); session.securityAuthKeyLen = USM_AUTH_KU_LEN; if (generate_Ku (session.securityAuthProto, session.securityAuthProtoLen, (u_char *)av[2], strlen (av[2]), session.securityAuthKey, &session.securityAuthKeyLen) != SNMPERR_SUCCESS) { err (false, "Error generating Ku from auth pass phrase"); } if (!(*ssp = snmp_open (&session))) err (false, "snmp_open failed"); } static void mib (char **av, struct snmp_session **ssp) { static int initialized = 0; if (av[1] == NULL) { err (false, "missing name"); return; } if (!initialized) { init_mib (); initialized = 1; } netsnmp_read_module (av[1]); /* prints its own errors */ } static void finish (char **av, struct snmp_session **ssp) { snmp_close (*ssp); *ssp = NULL; } static void help (void) { printf ("Valid commands are:\n"); printf (" start_v1 community\n"); printf (" start_v2c community\n"); printf (" start_v3 name passphrase\n"); printf (" mib name\n"); printf (" finish\n"); printf (" get oid\n"); printf (" set oid type value\n"); } static int docmd (char **av, char *hostname, struct snmp_session **ssp) { int rc = 0; if (av[0] != NULL) { if (strcmp (av[0], "help") == 0) help (); else if (strcmp (av[0], "get") == 0) get (av, ssp); else if (strcmp (av[0], "set") == 0) set (av, ssp); else if (strcmp (av[0], "start_v1") == 0) start_v1v2c (av, SNMP_VERSION_1, hostname, ssp); else if (strcmp (av[0], "start_v2c") == 0) start_v1v2c (av, SNMP_VERSION_2c, hostname, ssp); else if (strcmp (av[0], "start_v3") == 0) start_v3 (av, hostname, ssp); else if (strcmp (av[0], "mib") == 0) mib (av, ssp); else if (strcmp (av[0], "finish") == 0) finish (av, ssp); else printf ("type \"help\" for a list of commands\n"); } return rc; } static void shell (char *hostname) { char buf[128]; char **av; int rc = 0; struct snmp_session *ss = NULL; while (rc == 0) { printf ("snmppower> "); fflush (stdout); if (fgets (buf, sizeof (buf), stdin)) { av = argv_create (buf, ""); rc = docmd (av, hostname, &ss); argv_destroy (av); } else rc = 1; } } static void usage (void) { fprintf (stderr, "Usage: snmppower -h hostname\n"); exit(1); } int main (int argc, char *argv[]) { int c; char *hostname = NULL; err_init (basename(argv[0])); init_snmp ("snmppower"); while ((c = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != EOF) { switch (c) { case 'h': /* --hostname */ hostname = optarg; break; default: usage(); break; } } if (optind != argc) usage (); if (hostname == NULL) usage (); shell(hostname); exit(0); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/t/000077500000000000000000000000001467035776500136405ustar00rootroot00000000000000powerman-2.4.4/t/.gitignore000066400000000000000000000000411467035776500156230ustar00rootroot00000000000000/test-results /trash-directory.* powerman-2.4.4/t/Makefile.am000066400000000000000000000063211467035776500156760ustar00rootroot00000000000000AM_TESTS_ENVIRONMENT = TEST_EXTENSIONS = .t T_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \ $(top_srcdir)/config/tap-driver.sh clean-local: rm -fr trash-directory.* test-results .prove *.output # This list is included in both TESTS and dist_check_SCRIPTS. TESTSCRIPTS = \ t0000-sharness.t \ t0001-powerman-client.t \ t0002-pluglist.t \ t0003-api-client.t \ t0004-status-query.t \ t0005-telemetry.t \ t0006-on-off-cycle.t \ t0007-temperature.t \ t0008-beacon.t \ t0009-reset.t \ t0010-device-status.t \ t0011-device-timeout.t \ t0012-device-delay.t \ t0013-baytech-rpc3-nc.t \ t0014-baytech-rpc28-nc.t \ t0015-baytech-rpc3.t \ t0016-icebox-v3.t \ t0017-icebox-v2.t \ t0018-cyclades-pm.t \ t0019-insteon-plm.t \ t0020-digital-loggers-lpc.t \ t0021-remote-powerman.t \ t0023-sun-microsystems-ilom.t \ t0024-freeipmi.t \ t0025-openbmc.t \ t0026-llnl-sierra-cluster.t \ t0027-redfish-httppower.t \ t0028-issues.t \ t0029-redfish.t \ t0030-heartbeat-stonith.t \ t0031-llnl-mcr-cluster.t \ t0032-list.t \ t0033-valgrind.t \ t0034-redfishpower.t \ t0035-power-result.t \ t0036-diagnostics.t \ t0037-cray-ex.t \ t0038-cray-ex-rabbit.t \ t0039-llnl-el-capitan-cluster.t # make check runs these TAP tests directly (both scripts and programs) TESTS = \ $(TESTSCRIPTS) dist_check_SCRIPTS = \ $(TESTSCRIPTS) \ scripts/pm-sim.sh check-prep: $(MAKE) EXTRA_DIST= \ aggregate-results.sh \ sharness.sh \ etc/sierra_plugs.conf \ etc/mcr_plugs.conf \ etc/vpc.dev \ etc/redfishpower-setplugs.dev \ etc/redfishpower-setpath.dev \ etc/redfishpower-plugsub.dev \ etc/redfishpower-plugsub-blades.dev \ etc/redfishpower-parents-2-levels.dev \ etc/redfishpower-parents-3-levels.dev AM_CFLAGS = @WARNING_CFLAGS@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libcommon \ -I$(top_srcdir)/src/liblsd \ -I$(top_srcdir)/src/powerman common_ldadd = \ $(top_builddir)/src/liblsd/liblsd.la \ $(top_builddir)/src/libcommon/libcommon.la check_PROGRAMS = \ simulators/vpcd \ simulators/baytech \ simulators/icebox \ simulators/dli \ simulators/cyclades \ simulators/ipmipower \ simulators/ilom \ simulators/lom \ simulators/swpdu \ simulators/openbmc-httppower \ simulators/redfish-httppower simulators_vpcd_SOURCES = simulators/vpcd.c simulators_vpcd_LDADD = $(common_ldadd) simulators_baytech_SOURCES = simulators/baytech.c simulators_baytech_LDADD = $(common_ldadd) simulators_icebox_SOURCES = simulators/icebox.c simulators_icebox_LDADD = $(common_ldadd) simulators_swpdu_SOURCES = simulators/swpdu.c simulators_swpdu_LDADD = $(common_ldadd) simulators_dli_SOURCES = simulators/dli.c simulators_dli_LDADD = $(common_ldadd) simulators_ilom_SOURCES = simulators/ilom.c simulators_ilom_LDADD = $(common_ldadd) simulators_lom_SOURCES = simulators/lom.c simulators_lom_LDADD = $(common_ldadd) simulators_cyclades_SOURCES = simulators/cyclades.c simulators_cyclades_LDADD = $(common_ldadd) simulators_ipmipower_SOURCES = simulators/ipmipower.c simulators_ipmipower_LDADD = $(common_ldadd) simulators_openbmc_httppower_SOURCES = simulators/openbmc-httppower.c simulators_openbmc_httppower_LDADD = $(common_ldadd) simulators_redfish_httppower_SOURCES = simulators/redfish-httppower.c simulators_redfish_httppower_LDADD = $(common_ldadd) powerman-2.4.4/t/aggregate-results.sh000077500000000000000000000026751467035776500176360ustar00rootroot00000000000000#!/bin/sh # # Copyright (c) 2008-2012 Git project # # 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 http://www.gnu.org/licenses/ . failed_tests= fixed=0 success=0 failed=0 broken=0 total=0 for file; do while read type value; do case $type in '') continue ;; fixed) fixed=$(($fixed + $value)) ;; success) success=$(($success + $value)) ;; failed) failed=$(($failed + $value)) if test $value != 0; then test_name=$(expr "$file" : 'test-results/\(.*\)\.[0-9]*\.counts') failed_tests="$failed_tests $test_name" fi ;; broken) broken=$(($broken + $value)) ;; total) total=$(($total + $value)) ;; esac done <"$file" done if test -n "$failed_tests"; then printf "\nfailed test(s):$failed_tests\n\n" fi printf "%-8s%d\n" fixed $fixed printf "%-8s%d\n" success $success printf "%-8s%d\n" failed $failed printf "%-8s%d\n" broken $broken printf "%-8s%d\n" total $total powerman-2.4.4/t/etc/000077500000000000000000000000001467035776500144135ustar00rootroot00000000000000powerman-2.4.4/t/etc/mcr_plugs.conf000066400000000000000000001044651467035776500172670ustar00rootroot00000000000000# plug portion of MCR powerman.conf node "mcr0" "ice-r1-1" "1" node "mcr1" "ice-r1-1" "2" node "mcr2" "ice-r1-1" "3" node "mcr3" "ice-r1-1" "4" node "mcr4" "ice-r1-1" "5" node "mcr5" "ice-r1-1" "6" node "mcr6" "ice-r1-1" "7" node "mcr7" "ice-r1-1" "8" node "mcr8" "ice-r1-1" "9" node "mcr9" "ice-r1-1" "10" # node "mcr10" "ice-r2-1" "1" node "mcr11" "ice-r2-1" "2" node "mcr12" "ice-r2-1" "3" node "mcr13" "ice-r2-1" "4" node "mcr14" "ice-r2-1" "5" node "mcr15" "ice-r2-1" "6" node "mcr16" "ice-r2-1" "7" node "mcr17" "ice-r2-1" "8" node "mcr18" "ice-r2-1" "9" node "mcr19" "ice-r2-1" "10" # node "mcr20" "ice-r4-1" "1" node "mcr21" "ice-r4-1" "2" node "mcr22" "ice-r4-1" "3" node "mcr23" "ice-r4-1" "4" # node "mcr36" "ice-r4-1" "5" node "mcr37" "ice-r4-1" "6" node "mcr38" "ice-r4-1" "7" node "mcr39" "ice-r4-1" "8" # node "mcr24" "ice-r5-1" "1" node "mcr25" "ice-r5-1" "2" node "mcrj" "ice-r5-1" "4" # node "mcr26" "ice-r6-1" "1" node "mcr27" "ice-r6-1" "2" node "mcr28" "ice-r6-1" "3" node "mcr29" "ice-r6-1" "4" node "mcr30" "ice-r6-1" "5" node "mcr31" "ice-r6-1" "6" node "mcr32" "ice-r6-1" "7" node "mcr33" "ice-r6-1" "8" node "mcr34" "ice-r6-1" "9" node "mcr35" "ice-r6-1" "10" # #OLD node "mcr36" "ice-r7-1" "1" #OLD node "mcr37" "ice-r7-1" "2" #OLD node "mcr38" "ice-r7-1" "3" #OLD node "mcr39" "ice-r7-1" "4" node "mcr40" "ice-r7-1" "5" node "mcr41" "ice-r7-1" "6" node "mcr42" "ice-r7-1" "7" node "mcr43" "ice-r7-1" "8" node "mcr44" "ice-r7-1" "9" node "mcr45" "ice-r7-1" "10" # node "mcr46" "ice-r7-2" "1" node "mcr47" "ice-r7-2" "2" node "mcr48" "ice-r7-2" "3" node "mcr49" "ice-r7-2" "4" node "mcr50" "ice-r7-2" "5" node "mcr51" "ice-r7-2" "6" node "mcr52" "ice-r7-2" "7" node "mcr53" "ice-r7-2" "8" node "mcr54" "ice-r7-2" "9" node "mcr55" "ice-r7-2" "10" # node "mcr56" "ice-r7-3" "1" node "mcr57" "ice-r7-3" "2" node "mcr58" "ice-r7-3" "3" node "mcr59" "ice-r7-3" "4" node "mcr60" "ice-r7-3" "5" node "mcr61" "ice-r7-3" "6" node "mcr62" "ice-r7-3" "7" node "mcr63" "ice-r7-3" "8" node "mcr64" "ice-r7-3" "9" node "mcr65" "ice-r7-3" "10" # node "mcr66" "ice-r8-1" "1" node "mcr67" "ice-r8-1" "2" node "mcr68" "ice-r8-1" "3" node "mcr69" "ice-r8-1" "4" node "mcr70" "ice-r8-1" "5" node "mcr71" "ice-r8-1" "6" node "mcr72" "ice-r8-1" "7" node "mcr73" "ice-r8-1" "8" node "mcr74" "ice-r8-1" "9" node "mcr75" "ice-r8-1" "10" # node "mcr76" "ice-r8-2" "1" node "mcr77" "ice-r8-2" "2" node "mcr78" "ice-r8-2" "3" node "mcr79" "ice-r8-2" "4" node "mcr80" "ice-r8-2" "5" node "mcr81" "ice-r8-2" "6" node "mcr82" "ice-r8-2" "7" node "mcr83" "ice-r8-2" "8" node "mcr84" "ice-r8-2" "9" node "mcr85" "ice-r8-2" "10" # node "mcr86" "ice-r8-3" "1" node "mcr87" "ice-r8-3" "2" node "mcr88" "ice-r8-3" "3" node "mcr89" "ice-r8-3" "4" node "mcr90" "ice-r8-3" "5" node "mcr91" "ice-r8-3" "6" node "mcr92" "ice-r8-3" "7" node "mcr93" "ice-r8-3" "8" node "mcr94" "ice-r8-3" "9" node "mcr95" "ice-r8-3" "10" # # # CNSU0 # node "mcr96" "ice-r9-1" "1" node "mcr97" "ice-r9-1" "2" node "mcr98" "ice-r9-1" "3" node "mcr99" "ice-r9-1" "4" node "mcr100" "ice-r9-1" "5" node "mcr101" "ice-r9-1" "6" node "mcr102" "ice-r9-1" "7" node "mcr103" "ice-r9-1" "8" node "mcr104" "ice-r9-1" "9" node "mcr105" "ice-r9-1" "10" # node "mcr106" "ice-r9-2" "1" node "mcr107" "ice-r9-2" "2" node "mcr108" "ice-r9-2" "3" node "mcr109" "ice-r9-2" "4" node "mcr110" "ice-r9-2" "5" node "mcr111" "ice-r9-2" "6" node "mcr112" "ice-r9-2" "7" node "mcr113" "ice-r9-2" "8" node "mcr114" "ice-r9-2" "9" node "mcr115" "ice-r9-2" "10" # node "mcr116" "ice-r9-3" "1" node "mcr117" "ice-r9-3" "2" node "mcr118" "ice-r9-3" "3" node "mcr119" "ice-r9-3" "4" node "mcr120" "ice-r9-3" "5" node "mcr121" "ice-r9-3" "6" node "mcr122" "ice-r9-3" "7" node "mcr123" "ice-r9-3" "8" node "mcr124" "ice-r9-3" "9" node "mcr125" "ice-r9-3" "10" # node "mcr126" "ice-r9-4" "1" node "mcr127" "ice-r9-4" "2" node "mcr128" "ice-r9-4" "3" node "mcr129" "ice-r9-4" "4" node "mcr130" "ice-r9-4" "5" node "mcr131" "ice-r9-4" "6" node "mcr132" "ice-r9-4" "7" node "mcr133" "ice-r9-4" "8" node "mcr134" "ice-r9-4" "9" node "mcr135" "ice-r9-4" "10" # node "mcr136" "ice-r10-1" "1" node "mcr137" "ice-r10-1" "2" node "mcr138" "ice-r10-1" "3" node "mcr139" "ice-r10-1" "4" node "mcr140" "ice-r10-1" "5" node "mcr141" "ice-r10-1" "6" # node "mcr142" "ice-r10-2" "1" node "mcr143" "ice-r10-2" "2" node "mcr144" "ice-r10-2" "3" node "mcr145" "ice-r10-2" "4" node "mcr146" "ice-r10-2" "5" node "mcr147" "ice-r10-2" "6" node "mcr148" "ice-r10-2" "7" node "mcr149" "ice-r10-2" "8" node "mcr150" "ice-r10-2" "9" node "mcr151" "ice-r10-2" "10" # node "mcr152" "ice-r11-1" "1" node "mcr153" "ice-r11-1" "2" node "mcr154" "ice-r11-1" "3" node "mcr155" "ice-r11-1" "4" node "mcr156" "ice-r11-1" "5" node "mcr157" "ice-r11-1" "6" node "mcr158" "ice-r11-1" "7" node "mcr159" "ice-r11-1" "8" node "mcr160" "ice-r11-1" "9" node "mcr161" "ice-r11-1" "10" # node "mcr162" "ice-r11-2" "1" node "mcr163" "ice-r11-2" "2" node "mcr164" "ice-r11-2" "3" node "mcr165" "ice-r11-2" "4" node "mcr166" "ice-r11-2" "5" node "mcr167" "ice-r11-2" "6" node "mcr168" "ice-r11-2" "7" node "mcr169" "ice-r11-2" "8" node "mcr170" "ice-r11-2" "9" node "mcr171" "ice-r11-2" "10" # node "mcr172" "ice-r11-3" "1" node "mcr173" "ice-r11-3" "2" node "mcr174" "ice-r11-3" "3" node "mcr175" "ice-r11-3" "4" node "mcr176" "ice-r11-3" "5" node "mcr177" "ice-r11-3" "6" node "mcr178" "ice-r11-3" "7" node "mcr179" "ice-r11-3" "8" node "mcr180" "ice-r11-3" "9" node "mcr181" "ice-r11-3" "10" # node "mcr182" "ice-r11-4" "1" node "mcr183" "ice-r11-4" "2" node "mcr184" "ice-r11-4" "3" node "mcr185" "ice-r11-4" "4" node "mcr186" "ice-r11-4" "5" node "mcr187" "ice-r11-4" "6" node "mcr188" "ice-r11-4" "7" node "mcr189" "ice-r11-4" "8" node "mcr190" "ice-r11-4" "9" node "mcr191" "ice-r11-4" "10" # # CNSU1 # node "mcr192" "ice-r15-1" "1" node "mcr193" "ice-r15-1" "2" node "mcr194" "ice-r15-1" "3" node "mcr195" "ice-r15-1" "4" node "mcr196" "ice-r15-1" "5" node "mcr197" "ice-r15-1" "6" node "mcr198" "ice-r15-1" "7" node "mcr199" "ice-r15-1" "8" node "mcr200" "ice-r15-1" "9" node "mcr201" "ice-r15-1" "10" # node "mcr202" "ice-r15-2" "1" node "mcr203" "ice-r15-2" "2" node "mcr204" "ice-r15-2" "3" node "mcr205" "ice-r15-2" "4" node "mcr206" "ice-r15-2" "5" node "mcr207" "ice-r15-2" "6" node "mcr208" "ice-r15-2" "7" node "mcr209" "ice-r15-2" "8" node "mcr210" "ice-r15-2" "9" node "mcr211" "ice-r15-2" "10" # node "mcr212" "ice-r15-3" "1" node "mcr213" "ice-r15-3" "2" node "mcr214" "ice-r15-3" "3" node "mcr215" "ice-r15-3" "4" node "mcr216" "ice-r15-3" "5" node "mcr217" "ice-r15-3" "6" node "mcr218" "ice-r15-3" "7" node "mcr219" "ice-r15-3" "8" node "mcr220" "ice-r15-3" "9" node "mcr221" "ice-r15-3" "10" # node "mcr222" "ice-r15-4" "1" node "mcr223" "ice-r15-4" "2" node "mcr224" "ice-r15-4" "3" node "mcr225" "ice-r15-4" "4" node "mcr226" "ice-r15-4" "5" node "mcr227" "ice-r15-4" "6" node "mcr228" "ice-r15-4" "7" node "mcr229" "ice-r15-4" "8" node "mcr230" "ice-r15-4" "9" node "mcr231" "ice-r15-4" "10" # node "mcr232" "ice-r16-1" "1" node "mcr233" "ice-r16-1" "2" node "mcr234" "ice-r16-1" "3" node "mcr235" "ice-r16-1" "4" node "mcr236" "ice-r16-1" "5" node "mcr237" "ice-r16-1" "6" # node "mcr238" "ice-r16-2" "1" node "mcr239" "ice-r16-2" "2" node "mcr240" "ice-r16-2" "3" node "mcr241" "ice-r16-2" "4" node "mcr242" "ice-r16-2" "5" node "mcr243" "ice-r16-2" "6" node "mcr244" "ice-r16-2" "7" node "mcr245" "ice-r16-2" "8" node "mcr246" "ice-r16-2" "9" node "mcr247" "ice-r16-2" "10" # node "mcr248" "ice-r17-1" "1" node "mcr249" "ice-r17-1" "2" node "mcr250" "ice-r17-1" "3" node "mcr251" "ice-r17-1" "4" node "mcr252" "ice-r17-1" "5" node "mcr253" "ice-r17-1" "6" node "mcr254" "ice-r17-1" "7" node "mcr255" "ice-r17-1" "8" node "mcr256" "ice-r17-1" "9" node "mcr257" "ice-r17-1" "10" # node "mcr258" "ice-r17-2" "1" node "mcr259" "ice-r17-2" "2" node "mcr260" "ice-r17-2" "3" node "mcr261" "ice-r17-2" "4" node "mcr262" "ice-r17-2" "5" node "mcr263" "ice-r17-2" "6" node "mcr264" "ice-r17-2" "7" node "mcr265" "ice-r17-2" "8" node "mcr266" "ice-r17-2" "9" node "mcr267" "ice-r17-2" "10" # node "mcr268" "ice-r17-3" "1" node "mcr269" "ice-r17-3" "2" node "mcr270" "ice-r17-3" "3" node "mcr271" "ice-r17-3" "4" node "mcr272" "ice-r17-3" "5" node "mcr273" "ice-r17-3" "6" node "mcr274" "ice-r17-3" "7" node "mcr275" "ice-r17-3" "8" node "mcr276" "ice-r17-3" "9" node "mcr277" "ice-r17-3" "10" # node "mcr278" "ice-r17-4" "1" node "mcr279" "ice-r17-4" "2" node "mcr280" "ice-r17-4" "3" node "mcr281" "ice-r17-4" "4" node "mcr282" "ice-r17-4" "5" node "mcr283" "ice-r17-4" "6" node "mcr284" "ice-r17-4" "7" node "mcr285" "ice-r17-4" "8" node "mcr286" "ice-r17-4" "9" node "mcr287" "ice-r17-4" "10" # # CNSU2 # node "mcr288" "ice-r18-1" "1" node "mcr289" "ice-r18-1" "2" node "mcr290" "ice-r18-1" "3" node "mcr291" "ice-r18-1" "4" node "mcr292" "ice-r18-1" "5" node "mcr293" "ice-r18-1" "6" node "mcr294" "ice-r18-1" "7" node "mcr295" "ice-r18-1" "8" node "mcr296" "ice-r18-1" "9" node "mcr297" "ice-r18-1" "10" # node "mcr298" "ice-r18-2" "1" node "mcr299" "ice-r18-2" "2" node "mcr300" "ice-r18-2" "3" node "mcr301" "ice-r18-2" "4" node "mcr302" "ice-r18-2" "5" node "mcr303" "ice-r18-2" "6" node "mcr304" "ice-r18-2" "7" node "mcr305" "ice-r18-2" "8" node "mcr306" "ice-r18-2" "9" node "mcr307" "ice-r18-2" "10" # node "mcr308" "ice-r18-3" "1" node "mcr309" "ice-r18-3" "2" node "mcr310" "ice-r18-3" "3" node "mcr311" "ice-r18-3" "4" node "mcr312" "ice-r18-3" "5" node "mcr313" "ice-r18-3" "6" node "mcr314" "ice-r18-3" "7" node "mcr315" "ice-r18-3" "8" node "mcr316" "ice-r18-3" "9" node "mcr317" "ice-r18-3" "10" # node "mcr318" "ice-r18-4" "1" node "mcr319" "ice-r18-4" "2" node "mcr320" "ice-r18-4" "3" node "mcr321" "ice-r18-4" "4" node "mcr322" "ice-r18-4" "5" node "mcr323" "ice-r18-4" "6" node "mcr324" "ice-r18-4" "7" node "mcr325" "ice-r18-4" "8" node "mcr326" "ice-r18-4" "9" node "mcr327" "ice-r18-4" "10" # node "mcr328" "ice-r19-1" "1" node "mcr329" "ice-r19-1" "2" node "mcr330" "ice-r19-1" "3" node "mcr331" "ice-r19-1" "4" node "mcr332" "ice-r19-1" "5" node "mcr333" "ice-r19-1" "6" # node "mcr334" "ice-r19-2" "1" node "mcr335" "ice-r19-2" "2" node "mcr336" "ice-r19-2" "3" node "mcr337" "ice-r19-2" "4" node "mcr338" "ice-r19-2" "5" node "mcr339" "ice-r19-2" "6" node "mcr340" "ice-r19-2" "7" node "mcr341" "ice-r19-2" "8" node "mcr342" "ice-r19-2" "9" node "mcr343" "ice-r19-2" "10" # node "mcr344" "ice-r20-1" "1" node "mcr345" "ice-r20-1" "2" node "mcr346" "ice-r20-1" "3" node "mcr347" "ice-r20-1" "4" node "mcr348" "ice-r20-1" "5" node "mcr349" "ice-r20-1" "6" node "mcr350" "ice-r20-1" "7" node "mcr351" "ice-r20-1" "8" node "mcr352" "ice-r20-1" "9" node "mcr353" "ice-r20-1" "10" # node "mcr354" "ice-r20-2" "1" node "mcr355" "ice-r20-2" "2" node "mcr356" "ice-r20-2" "3" node "mcr357" "ice-r20-2" "4" node "mcr358" "ice-r20-2" "5" node "mcr359" "ice-r20-2" "6" node "mcr360" "ice-r20-2" "7" node "mcr361" "ice-r20-2" "8" node "mcr362" "ice-r20-2" "9" node "mcr363" "ice-r20-2" "10" # node "mcr364" "ice-r20-3" "1" node "mcr365" "ice-r20-3" "2" node "mcr366" "ice-r20-3" "3" node "mcr367" "ice-r20-3" "4" node "mcr368" "ice-r20-3" "5" node "mcr369" "ice-r20-3" "6" node "mcr370" "ice-r20-3" "7" node "mcr371" "ice-r20-3" "8" node "mcr372" "ice-r20-3" "9" node "mcr373" "ice-r20-3" "10" # node "mcr374" "ice-r20-4" "1" node "mcr375" "ice-r20-4" "2" node "mcr376" "ice-r20-4" "3" node "mcr377" "ice-r20-4" "4" node "mcr378" "ice-r20-4" "5" node "mcr379" "ice-r20-4" "6" node "mcr380" "ice-r20-4" "7" node "mcr381" "ice-r20-4" "8" node "mcr382" "ice-r20-4" "9" node "mcr383" "ice-r20-4" "10" # # CNSU3 # node "mcr384" "ice-r23-1" "1" node "mcr385" "ice-r23-1" "2" node "mcr386" "ice-r23-1" "3" node "mcr387" "ice-r23-1" "4" node "mcr388" "ice-r23-1" "5" node "mcr389" "ice-r23-1" "6" node "mcr390" "ice-r23-1" "7" node "mcr391" "ice-r23-1" "8" node "mcr392" "ice-r23-1" "9" node "mcr393" "ice-r23-1" "10" # node "mcr394" "ice-r23-2" "1" node "mcr395" "ice-r23-2" "2" node "mcr396" "ice-r23-2" "3" node "mcr397" "ice-r23-2" "4" node "mcr398" "ice-r23-2" "5" node "mcr399" "ice-r23-2" "6" node "mcr400" "ice-r23-2" "7" node "mcr401" "ice-r23-2" "8" node "mcr402" "ice-r23-2" "9" node "mcr403" "ice-r23-2" "10" # node "mcr404" "ice-r23-3" "1" node "mcr405" "ice-r23-3" "2" node "mcr406" "ice-r23-3" "3" node "mcr407" "ice-r23-3" "4" node "mcr408" "ice-r23-3" "5" node "mcr409" "ice-r23-3" "6" node "mcr410" "ice-r23-3" "7" node "mcr411" "ice-r23-3" "8" node "mcr412" "ice-r23-3" "9" node "mcr413" "ice-r23-3" "10" # node "mcr414" "ice-r23-4" "1" node "mcr415" "ice-r23-4" "2" node "mcr416" "ice-r23-4" "3" node "mcr417" "ice-r23-4" "4" node "mcr418" "ice-r23-4" "5" node "mcr419" "ice-r23-4" "6" node "mcr420" "ice-r23-4" "7" node "mcr421" "ice-r23-4" "8" node "mcr422" "ice-r23-4" "9" node "mcr423" "ice-r23-4" "10" # node "mcr424" "ice-r24-1" "1" node "mcr425" "ice-r24-1" "2" node "mcr426" "ice-r24-1" "3" node "mcr427" "ice-r24-1" "4" node "mcr428" "ice-r24-1" "5" node "mcr429" "ice-r24-1" "6" # node "mcr430" "ice-r24-2" "1" node "mcr431" "ice-r24-2" "2" node "mcr432" "ice-r24-2" "3" node "mcr433" "ice-r24-2" "4" node "mcr434" "ice-r24-2" "5" node "mcr435" "ice-r24-2" "6" node "mcr436" "ice-r24-2" "7" node "mcr437" "ice-r24-2" "8" node "mcr438" "ice-r24-2" "9" node "mcr439" "ice-r24-2" "10" # node "mcr440" "ice-r25-1" "1" node "mcr441" "ice-r25-1" "2" node "mcr442" "ice-r25-1" "3" node "mcr443" "ice-r25-1" "4" node "mcr444" "ice-r25-1" "5" node "mcr445" "ice-r25-1" "6" node "mcr446" "ice-r25-1" "7" node "mcr447" "ice-r25-1" "8" node "mcr448" "ice-r25-1" "9" node "mcr449" "ice-r25-1" "10" # node "mcr450" "ice-r25-2" "1" node "mcr451" "ice-r25-2" "2" node "mcr452" "ice-r25-2" "3" node "mcr453" "ice-r25-2" "4" node "mcr454" "ice-r25-2" "5" node "mcr455" "ice-r25-2" "6" node "mcr456" "ice-r25-2" "7" node "mcr457" "ice-r25-2" "8" node "mcr458" "ice-r25-2" "9" node "mcr459" "ice-r25-2" "10" # node "mcr460" "ice-r25-3" "1" node "mcr461" "ice-r25-3" "2" node "mcr462" "ice-r25-3" "3" node "mcr463" "ice-r25-3" "4" node "mcr464" "ice-r25-3" "5" node "mcr465" "ice-r25-3" "6" node "mcr466" "ice-r25-3" "7" node "mcr467" "ice-r25-3" "8" node "mcr468" "ice-r25-3" "9" node "mcr469" "ice-r25-3" "10" # node "mcr470" "ice-r25-4" "1" node "mcr471" "ice-r25-4" "2" node "mcr472" "ice-r25-4" "3" node "mcr473" "ice-r25-4" "4" node "mcr474" "ice-r25-4" "5" node "mcr475" "ice-r25-4" "6" node "mcr476" "ice-r25-4" "7" node "mcr477" "ice-r25-4" "8" node "mcr478" "ice-r25-4" "9" node "mcr479" "ice-r25-4" "10" # # CNSU4 # node "mcr480" "ice-r26-1" "1" node "mcr481" "ice-r26-1" "2" node "mcr482" "ice-r26-1" "3" node "mcr483" "ice-r26-1" "4" node "mcr484" "ice-r26-1" "5" node "mcr485" "ice-r26-1" "6" node "mcr486" "ice-r26-1" "7" node "mcr487" "ice-r26-1" "8" node "mcr488" "ice-r26-1" "9" node "mcr489" "ice-r26-1" "10" # node "mcr490" "ice-r26-2" "1" node "mcr491" "ice-r26-2" "2" node "mcr492" "ice-r26-2" "3" node "mcr493" "ice-r26-2" "4" node "mcr494" "ice-r26-2" "5" node "mcr495" "ice-r26-2" "6" node "mcr496" "ice-r26-2" "7" node "mcr497" "ice-r26-2" "8" node "mcr498" "ice-r26-2" "9" node "mcr499" "ice-r26-2" "10" # node "mcr500" "ice-r26-3" "1" node "mcr501" "ice-r26-3" "2" node "mcr502" "ice-r26-3" "3" node "mcr503" "ice-r26-3" "4" node "mcr504" "ice-r26-3" "5" node "mcr505" "ice-r26-3" "6" node "mcr506" "ice-r26-3" "7" node "mcr507" "ice-r26-3" "8" node "mcr508" "ice-r26-3" "9" node "mcr509" "ice-r26-3" "10" # node "mcr510" "ice-r26-4" "1" node "mcr511" "ice-r26-4" "2" node "mcr512" "ice-r26-4" "3" node "mcr513" "ice-r26-4" "4" node "mcr514" "ice-r26-4" "5" node "mcr515" "ice-r26-4" "6" node "mcr516" "ice-r26-4" "7" node "mcr517" "ice-r26-4" "8" node "mcr518" "ice-r26-4" "9" node "mcr519" "ice-r26-4" "10" # node "mcr520" "ice-r27-1" "1" node "mcr521" "ice-r27-1" "2" node "mcr522" "ice-r27-1" "3" node "mcr523" "ice-r27-1" "4" node "mcr524" "ice-r27-1" "5" node "mcr525" "ice-r27-1" "6" # node "mcr526" "ice-r27-2" "1" node "mcr527" "ice-r27-2" "2" node "mcr528" "ice-r27-2" "3" node "mcr529" "ice-r27-2" "4" node "mcr530" "ice-r27-2" "5" node "mcr531" "ice-r27-2" "6" node "mcr532" "ice-r27-2" "7" node "mcr533" "ice-r27-2" "8" node "mcr534" "ice-r27-2" "9" node "mcr535" "ice-r27-2" "10" # node "mcr536" "ice-r28-1" "1" node "mcr537" "ice-r28-1" "2" node "mcr538" "ice-r28-1" "3" node "mcr539" "ice-r28-1" "4" node "mcr540" "ice-r28-1" "5" node "mcr541" "ice-r28-1" "6" node "mcr542" "ice-r28-1" "7" node "mcr543" "ice-r28-1" "8" node "mcr544" "ice-r28-1" "9" node "mcr545" "ice-r28-1" "10" # node "mcr546" "ice-r28-2" "1" node "mcr547" "ice-r28-2" "2" node "mcr548" "ice-r28-2" "3" node "mcr549" "ice-r28-2" "4" node "mcr550" "ice-r28-2" "5" node "mcr551" "ice-r28-2" "6" node "mcr552" "ice-r28-2" "7" node "mcr553" "ice-r28-2" "8" node "mcr554" "ice-r28-2" "9" node "mcr555" "ice-r28-2" "10" # node "mcr556" "ice-r28-3" "1" node "mcr557" "ice-r28-3" "2" node "mcr558" "ice-r28-3" "3" node "mcr559" "ice-r28-3" "4" node "mcr560" "ice-r28-3" "5" node "mcr561" "ice-r28-3" "6" node "mcr562" "ice-r28-3" "7" node "mcr563" "ice-r28-3" "8" node "mcr564" "ice-r28-3" "9" node "mcr565" "ice-r28-3" "10" # node "mcr566" "ice-r28-4" "1" node "mcr567" "ice-r28-4" "2" node "mcr568" "ice-r28-4" "3" node "mcr569" "ice-r28-4" "4" node "mcr570" "ice-r28-4" "5" node "mcr571" "ice-r28-4" "6" node "mcr572" "ice-r28-4" "7" node "mcr573" "ice-r28-4" "8" node "mcr574" "ice-r28-4" "9" node "mcr575" "ice-r28-4" "10" # # CNSU5 # node "mcr576" "ice-r29-1" "1" node "mcr577" "ice-r29-1" "2" node "mcr578" "ice-r29-1" "3" node "mcr579" "ice-r29-1" "4" node "mcr580" "ice-r29-1" "5" node "mcr581" "ice-r29-1" "6" node "mcr582" "ice-r29-1" "7" node "mcr583" "ice-r29-1" "8" node "mcr584" "ice-r29-1" "9" node "mcr585" "ice-r29-1" "10" # node "mcr586" "ice-r29-2" "1" node "mcr587" "ice-r29-2" "2" node "mcr588" "ice-r29-2" "3" node "mcr589" "ice-r29-2" "4" node "mcr590" "ice-r29-2" "5" node "mcr591" "ice-r29-2" "6" node "mcr592" "ice-r29-2" "7" node "mcr593" "ice-r29-2" "8" node "mcr594" "ice-r29-2" "9" node "mcr595" "ice-r29-2" "10" # node "mcr596" "ice-r29-3" "1" node "mcr597" "ice-r29-3" "2" node "mcr598" "ice-r29-3" "3" node "mcr599" "ice-r29-3" "4" node "mcr600" "ice-r29-3" "5" node "mcr601" "ice-r29-3" "6" node "mcr602" "ice-r29-3" "7" node "mcr603" "ice-r29-3" "8" node "mcr604" "ice-r29-3" "9" node "mcr605" "ice-r29-3" "10" # node "mcr606" "ice-r29-4" "1" node "mcr607" "ice-r29-4" "2" node "mcr608" "ice-r29-4" "3" node "mcr609" "ice-r29-4" "4" node "mcr610" "ice-r29-4" "5" node "mcr611" "ice-r29-4" "6" node "mcr612" "ice-r29-4" "7" node "mcr613" "ice-r29-4" "8" node "mcr614" "ice-r29-4" "9" node "mcr615" "ice-r29-4" "10" # node "mcr616" "ice-r30-1" "1" node "mcr617" "ice-r30-1" "2" node "mcr618" "ice-r30-1" "3" node "mcr619" "ice-r30-1" "4" node "mcr620" "ice-r30-1" "5" node "mcr621" "ice-r30-1" "6" # node "mcr622" "ice-r30-2" "1" node "mcr623" "ice-r30-2" "2" node "mcr624" "ice-r30-2" "3" node "mcr625" "ice-r30-2" "4" node "mcr626" "ice-r30-2" "5" node "mcr627" "ice-r30-2" "6" node "mcr628" "ice-r30-2" "7" node "mcr629" "ice-r30-2" "8" node "mcr630" "ice-r30-2" "9" node "mcr631" "ice-r30-2" "10" # node "mcr632" "ice-r31-1" "1" node "mcr633" "ice-r31-1" "2" node "mcr634" "ice-r31-1" "3" node "mcr635" "ice-r31-1" "4" node "mcr636" "ice-r31-1" "5" node "mcr637" "ice-r31-1" "6" node "mcr638" "ice-r31-1" "7" node "mcr639" "ice-r31-1" "8" node "mcr640" "ice-r31-1" "9" node "mcr641" "ice-r31-1" "10" # node "mcr642" "ice-r31-2" "1" node "mcr643" "ice-r31-2" "2" node "mcr644" "ice-r31-2" "3" node "mcr645" "ice-r31-2" "4" node "mcr646" "ice-r31-2" "5" node "mcr647" "ice-r31-2" "6" node "mcr648" "ice-r31-2" "7" node "mcr649" "ice-r31-2" "8" node "mcr650" "ice-r31-2" "9" node "mcr651" "ice-r31-2" "10" # node "mcr652" "ice-r31-3" "1" node "mcr653" "ice-r31-3" "2" node "mcr654" "ice-r31-3" "3" node "mcr655" "ice-r31-3" "4" node "mcr656" "ice-r31-3" "5" node "mcr657" "ice-r31-3" "6" node "mcr658" "ice-r31-3" "7" node "mcr659" "ice-r31-3" "8" node "mcr660" "ice-r31-3" "9" node "mcr661" "ice-r31-3" "10" # node "mcr662" "ice-r31-4" "1" node "mcr663" "ice-r31-4" "2" node "mcr664" "ice-r31-4" "3" node "mcr665" "ice-r31-4" "4" node "mcr666" "ice-r31-4" "5" node "mcr667" "ice-r31-4" "6" node "mcr668" "ice-r31-4" "7" node "mcr669" "ice-r31-4" "8" node "mcr670" "ice-r31-4" "9" node "mcr671" "ice-r31-4" "10" # # CNSU6 # node "mcr672" "ice-r32-1" "1" node "mcr673" "ice-r32-1" "2" node "mcr674" "ice-r32-1" "3" node "mcr675" "ice-r32-1" "4" node "mcr676" "ice-r32-1" "5" node "mcr677" "ice-r32-1" "6" node "mcr678" "ice-r32-1" "7" node "mcr679" "ice-r32-1" "8" node "mcr680" "ice-r32-1" "9" node "mcr681" "ice-r32-1" "10" # node "mcr682" "ice-r32-2" "1" node "mcr683" "ice-r32-2" "2" node "mcr684" "ice-r32-2" "3" node "mcr685" "ice-r32-2" "4" node "mcr686" "ice-r32-2" "5" node "mcr687" "ice-r32-2" "6" node "mcr688" "ice-r32-2" "7" node "mcr689" "ice-r32-2" "8" node "mcr690" "ice-r32-2" "9" node "mcr691" "ice-r32-2" "10" # node "mcr692" "ice-r32-3" "1" node "mcr693" "ice-r32-3" "2" node "mcr694" "ice-r32-3" "3" node "mcr695" "ice-r32-3" "4" node "mcr696" "ice-r32-3" "5" node "mcr697" "ice-r32-3" "6" node "mcr698" "ice-r32-3" "7" node "mcr699" "ice-r32-3" "8" node "mcr700" "ice-r32-3" "9" node "mcr701" "ice-r32-3" "10" # node "mcr702" "ice-r32-4" "1" node "mcr703" "ice-r32-4" "2" node "mcr704" "ice-r32-4" "3" node "mcr705" "ice-r32-4" "4" node "mcr706" "ice-r32-4" "5" node "mcr707" "ice-r32-4" "6" node "mcr708" "ice-r32-4" "7" node "mcr709" "ice-r32-4" "8" node "mcr710" "ice-r32-4" "9" node "mcr711" "ice-r32-4" "10" # node "mcr712" "ice-r33-1" "1" node "mcr713" "ice-r33-1" "2" node "mcr714" "ice-r33-1" "3" node "mcr715" "ice-r33-1" "4" node "mcr716" "ice-r33-1" "5" node "mcr717" "ice-r33-1" "6" # node "mcr718" "ice-r33-2" "1" node "mcr719" "ice-r33-2" "2" node "mcr720" "ice-r33-2" "3" node "mcr721" "ice-r33-2" "4" node "mcr722" "ice-r33-2" "5" node "mcr723" "ice-r33-2" "6" node "mcr724" "ice-r33-2" "7" node "mcr725" "ice-r33-2" "8" node "mcr726" "ice-r33-2" "9" node "mcr727" "ice-r33-2" "10" # node "mcr728" "ice-r34-1" "1" node "mcr729" "ice-r34-1" "2" node "mcr730" "ice-r34-1" "3" node "mcr731" "ice-r34-1" "4" node "mcr732" "ice-r34-1" "5" node "mcr733" "ice-r34-1" "6" node "mcr734" "ice-r34-1" "7" node "mcr735" "ice-r34-1" "8" node "mcr736" "ice-r34-1" "9" node "mcr737" "ice-r34-1" "10" # node "mcr738" "ice-r34-2" "1" node "mcr739" "ice-r34-2" "2" node "mcr740" "ice-r34-2" "3" node "mcr741" "ice-r34-2" "4" node "mcr742" "ice-r34-2" "5" node "mcr743" "ice-r34-2" "6" node "mcr744" "ice-r34-2" "7" node "mcr745" "ice-r34-2" "8" node "mcr746" "ice-r34-2" "9" node "mcr747" "ice-r34-2" "10" # node "mcr748" "ice-r34-3" "1" node "mcr749" "ice-r34-3" "2" node "mcr750" "ice-r34-3" "3" node "mcr751" "ice-r34-3" "4" node "mcr752" "ice-r34-3" "5" node "mcr753" "ice-r34-3" "6" node "mcr754" "ice-r34-3" "7" node "mcr755" "ice-r34-3" "8" node "mcr756" "ice-r34-3" "9" node "mcr757" "ice-r34-3" "10" # node "mcr758" "ice-r34-4" "1" node "mcr759" "ice-r34-4" "2" node "mcr760" "ice-r34-4" "3" node "mcr761" "ice-r34-4" "4" node "mcr762" "ice-r34-4" "5" node "mcr763" "ice-r34-4" "6" node "mcr764" "ice-r34-4" "7" node "mcr765" "ice-r34-4" "8" node "mcr766" "ice-r34-4" "9" node "mcr767" "ice-r34-4" "10" # # CNSU7 # node "mcr768" "ice-r35-1" "1" node "mcr769" "ice-r35-1" "2" node "mcr770" "ice-r35-1" "3" node "mcr771" "ice-r35-1" "4" node "mcr772" "ice-r35-1" "5" node "mcr773" "ice-r35-1" "6" node "mcr774" "ice-r35-1" "7" node "mcr775" "ice-r35-1" "8" node "mcr776" "ice-r35-1" "9" node "mcr777" "ice-r35-1" "10" # node "mcr778" "ice-r35-2" "1" node "mcr779" "ice-r35-2" "2" node "mcr780" "ice-r35-2" "3" node "mcr781" "ice-r35-2" "4" node "mcr782" "ice-r35-2" "5" node "mcr783" "ice-r35-2" "6" node "mcr784" "ice-r35-2" "7" node "mcr785" "ice-r35-2" "8" node "mcr786" "ice-r35-2" "9" node "mcr787" "ice-r35-2" "10" # node "mcr788" "ice-r35-3" "1" node "mcr789" "ice-r35-3" "2" node "mcr790" "ice-r35-3" "3" node "mcr791" "ice-r35-3" "4" node "mcr792" "ice-r35-3" "5" node "mcr793" "ice-r35-3" "6" node "mcr794" "ice-r35-3" "7" node "mcr795" "ice-r35-3" "8" node "mcr796" "ice-r35-3" "9" node "mcr797" "ice-r35-3" "10" # node "mcr798" "ice-r35-4" "1" node "mcr799" "ice-r35-4" "2" node "mcr800" "ice-r35-4" "3" node "mcr801" "ice-r35-4" "4" node "mcr802" "ice-r35-4" "5" node "mcr803" "ice-r35-4" "6" node "mcr804" "ice-r35-4" "7" node "mcr805" "ice-r35-4" "8" node "mcr806" "ice-r35-4" "9" node "mcr807" "ice-r35-4" "10" # node "mcr808" "ice-r36-1" "1" node "mcr809" "ice-r36-1" "2" node "mcr810" "ice-r36-1" "3" node "mcr811" "ice-r36-1" "4" node "mcr812" "ice-r36-1" "5" node "mcr813" "ice-r36-1" "6" # node "mcr814" "ice-r36-2" "1" node "mcr815" "ice-r36-2" "2" node "mcr816" "ice-r36-2" "3" node "mcr817" "ice-r36-2" "4" node "mcr818" "ice-r36-2" "5" node "mcr819" "ice-r36-2" "6" node "mcr820" "ice-r36-2" "7" node "mcr821" "ice-r36-2" "8" node "mcr822" "ice-r36-2" "9" node "mcr823" "ice-r36-2" "10" # node "mcr824" "ice-r37-1" "1" node "mcr825" "ice-r37-1" "2" node "mcr826" "ice-r37-1" "3" node "mcr827" "ice-r37-1" "4" node "mcr828" "ice-r37-1" "5" node "mcr829" "ice-r37-1" "6" node "mcr830" "ice-r37-1" "7" node "mcr831" "ice-r37-1" "8" node "mcr832" "ice-r37-1" "9" node "mcr833" "ice-r37-1" "10" # node "mcr834" "ice-r37-2" "1" node "mcr835" "ice-r37-2" "2" node "mcr836" "ice-r37-2" "3" node "mcr837" "ice-r37-2" "4" node "mcr838" "ice-r37-2" "5" node "mcr839" "ice-r37-2" "6" node "mcr840" "ice-r37-2" "7" node "mcr841" "ice-r37-2" "8" node "mcr842" "ice-r37-2" "9" node "mcr843" "ice-r37-2" "10" # node "mcr844" "ice-r37-3" "1" node "mcr845" "ice-r37-3" "2" node "mcr846" "ice-r37-3" "3" node "mcr847" "ice-r37-3" "4" node "mcr848" "ice-r37-3" "5" node "mcr849" "ice-r37-3" "6" node "mcr850" "ice-r37-3" "7" node "mcr851" "ice-r37-3" "8" node "mcr852" "ice-r37-3" "9" node "mcr853" "ice-r37-3" "10" # node "mcr854" "ice-r37-4" "1" node "mcr855" "ice-r37-4" "2" node "mcr856" "ice-r37-4" "3" node "mcr857" "ice-r37-4" "4" node "mcr858" "ice-r37-4" "5" node "mcr859" "ice-r37-4" "6" node "mcr860" "ice-r37-4" "7" node "mcr861" "ice-r37-4" "8" node "mcr862" "ice-r37-4" "9" node "mcr863" "ice-r37-4" "10" # # CNSU8 # node "mcr864" "ice-r38-1" "1" node "mcr865" "ice-r38-1" "2" node "mcr866" "ice-r38-1" "3" node "mcr867" "ice-r38-1" "4" node "mcr868" "ice-r38-1" "5" node "mcr869" "ice-r38-1" "6" node "mcr870" "ice-r38-1" "7" node "mcr871" "ice-r38-1" "8" node "mcr872" "ice-r38-1" "9" node "mcr873" "ice-r38-1" "10" # node "mcr874" "ice-r38-2" "1" node "mcr875" "ice-r38-2" "2" node "mcr876" "ice-r38-2" "3" node "mcr877" "ice-r38-2" "4" node "mcr878" "ice-r38-2" "5" node "mcr879" "ice-r38-2" "6" node "mcr880" "ice-r38-2" "7" node "mcr881" "ice-r38-2" "8" node "mcr882" "ice-r38-2" "9" node "mcr883" "ice-r38-2" "10" # node "mcr884" "ice-r38-3" "1" node "mcr885" "ice-r38-3" "2" node "mcr886" "ice-r38-3" "3" node "mcr887" "ice-r38-3" "4" node "mcr888" "ice-r38-3" "5" node "mcr889" "ice-r38-3" "6" node "mcr890" "ice-r38-3" "7" node "mcr891" "ice-r38-3" "8" node "mcr892" "ice-r38-3" "9" node "mcr893" "ice-r38-3" "10" # node "mcr894" "ice-r38-4" "1" node "mcr895" "ice-r38-4" "2" node "mcr896" "ice-r38-4" "3" node "mcr897" "ice-r38-4" "4" node "mcr898" "ice-r38-4" "5" node "mcr899" "ice-r38-4" "6" node "mcr900" "ice-r38-4" "7" node "mcr901" "ice-r38-4" "8" node "mcr902" "ice-r38-4" "9" node "mcr903" "ice-r38-4" "10" # node "mcr904" "ice-r39-1" "1" node "mcr905" "ice-r39-1" "2" node "mcr906" "ice-r39-1" "3" node "mcr907" "ice-r39-1" "4" node "mcr908" "ice-r39-1" "5" node "mcr909" "ice-r39-1" "6" # node "mcr910" "ice-r39-2" "1" node "mcr911" "ice-r39-2" "2" node "mcr912" "ice-r39-2" "3" node "mcr913" "ice-r39-2" "4" node "mcr914" "ice-r39-2" "5" node "mcr915" "ice-r39-2" "6" node "mcr916" "ice-r39-2" "7" node "mcr917" "ice-r39-2" "8" node "mcr918" "ice-r39-2" "9" node "mcr919" "ice-r39-2" "10" # node "mcr920" "ice-r40-1" "1" node "mcr921" "ice-r40-1" "2" node "mcr922" "ice-r40-1" "3" node "mcr923" "ice-r40-1" "4" node "mcr924" "ice-r40-1" "5" node "mcr925" "ice-r40-1" "6" node "mcr926" "ice-r40-1" "7" node "mcr927" "ice-r40-1" "8" node "mcr928" "ice-r40-1" "9" node "mcr929" "ice-r40-1" "10" # node "mcr930" "ice-r40-2" "1" node "mcr931" "ice-r40-2" "2" node "mcr932" "ice-r40-2" "3" node "mcr933" "ice-r40-2" "4" node "mcr934" "ice-r40-2" "5" node "mcr935" "ice-r40-2" "6" node "mcr936" "ice-r40-2" "7" node "mcr937" "ice-r40-2" "8" node "mcr938" "ice-r40-2" "9" node "mcr939" "ice-r40-2" "10" # node "mcr940" "ice-r40-3" "1" node "mcr941" "ice-r40-3" "2" node "mcr942" "ice-r40-3" "3" node "mcr943" "ice-r40-3" "4" node "mcr944" "ice-r40-3" "5" node "mcr945" "ice-r40-3" "6" node "mcr946" "ice-r40-3" "7" node "mcr947" "ice-r40-3" "8" node "mcr948" "ice-r40-3" "9" node "mcr949" "ice-r40-3" "10" # node "mcr950" "ice-r40-4" "1" node "mcr951" "ice-r40-4" "2" node "mcr952" "ice-r40-4" "3" node "mcr953" "ice-r40-4" "4" node "mcr954" "ice-r40-4" "5" node "mcr955" "ice-r40-4" "6" node "mcr956" "ice-r40-4" "7" node "mcr957" "ice-r40-4" "8" node "mcr958" "ice-r40-4" "9" node "mcr959" "ice-r40-4" "10" # # CNSU9 # node "mcr960" "ice-r41-1" "1" node "mcr961" "ice-r41-1" "2" node "mcr962" "ice-r41-1" "3" node "mcr963" "ice-r41-1" "4" node "mcr964" "ice-r41-1" "5" node "mcr965" "ice-r41-1" "6" node "mcr966" "ice-r41-1" "7" node "mcr967" "ice-r41-1" "8" node "mcr968" "ice-r41-1" "9" node "mcr969" "ice-r41-1" "10" # node "mcr970" "ice-r41-2" "1" node "mcr971" "ice-r41-2" "2" node "mcr972" "ice-r41-2" "3" node "mcr973" "ice-r41-2" "4" node "mcr974" "ice-r41-2" "5" node "mcr975" "ice-r41-2" "6" node "mcr976" "ice-r41-2" "7" node "mcr977" "ice-r41-2" "8" node "mcr978" "ice-r41-2" "9" node "mcr979" "ice-r41-2" "10" # node "mcr980" "ice-r41-3" "1" node "mcr981" "ice-r41-3" "2" node "mcr982" "ice-r41-3" "3" node "mcr983" "ice-r41-3" "4" node "mcr984" "ice-r41-3" "5" node "mcr985" "ice-r41-3" "6" node "mcr986" "ice-r41-3" "7" node "mcr987" "ice-r41-3" "8" node "mcr988" "ice-r41-3" "9" node "mcr989" "ice-r41-3" "10" # node "mcr990" "ice-r41-4" "1" node "mcr991" "ice-r41-4" "2" node "mcr992" "ice-r41-4" "3" node "mcr993" "ice-r41-4" "4" node "mcr994" "ice-r41-4" "5" node "mcr995" "ice-r41-4" "6" node "mcr996" "ice-r41-4" "7" node "mcr997" "ice-r41-4" "8" node "mcr998" "ice-r41-4" "9" node "mcr999" "ice-r41-4" "10" # node "mcr1000" "ice-r42-1" "1" node "mcr1001" "ice-r42-1" "2" node "mcr1002" "ice-r42-1" "3" node "mcr1003" "ice-r42-1" "4" node "mcr1004" "ice-r42-1" "5" node "mcr1005" "ice-r42-1" "6" # node "mcr1006" "ice-r42-2" "1" node "mcr1007" "ice-r42-2" "2" node "mcr1008" "ice-r42-2" "3" node "mcr1009" "ice-r42-2" "4" node "mcr1010" "ice-r42-2" "5" node "mcr1011" "ice-r42-2" "6" node "mcr1012" "ice-r42-2" "7" node "mcr1013" "ice-r42-2" "8" node "mcr1014" "ice-r42-2" "9" node "mcr1015" "ice-r42-2" "10" # node "mcr1016" "ice-r43-1" "1" node "mcr1017" "ice-r43-1" "2" node "mcr1018" "ice-r43-1" "3" node "mcr1019" "ice-r43-1" "4" node "mcr1020" "ice-r43-1" "5" node "mcr1021" "ice-r43-1" "6" node "mcr1022" "ice-r43-1" "7" node "mcr1023" "ice-r43-1" "8" node "mcr1024" "ice-r43-1" "9" node "mcr1025" "ice-r43-1" "10" # node "mcr1026" "ice-r43-2" "1" node "mcr1027" "ice-r43-2" "2" node "mcr1028" "ice-r43-2" "3" node "mcr1029" "ice-r43-2" "4" node "mcr1030" "ice-r43-2" "5" node "mcr1031" "ice-r43-2" "6" node "mcr1032" "ice-r43-2" "7" node "mcr1033" "ice-r43-2" "8" node "mcr1034" "ice-r43-2" "9" node "mcr1035" "ice-r43-2" "10" # node "mcr1036" "ice-r43-3" "1" node "mcr1037" "ice-r43-3" "2" node "mcr1038" "ice-r43-3" "3" node "mcr1039" "ice-r43-3" "4" node "mcr1040" "ice-r43-3" "5" node "mcr1041" "ice-r43-3" "6" node "mcr1042" "ice-r43-3" "7" node "mcr1043" "ice-r43-3" "8" node "mcr1044" "ice-r43-3" "9" node "mcr1045" "ice-r43-3" "10" # node "mcr1046" "ice-r43-4" "1" node "mcr1047" "ice-r43-4" "2" node "mcr1048" "ice-r43-4" "3" node "mcr1049" "ice-r43-4" "4" node "mcr1050" "ice-r43-4" "5" node "mcr1051" "ice-r43-4" "6" node "mcr1052" "ice-r43-4" "7" node "mcr1053" "ice-r43-4" "8" node "mcr1054" "ice-r43-4" "9" node "mcr1055" "ice-r43-4" "10" # # CNSU10 # node "mcr1056" "ice-r12-1" "1" node "mcr1057" "ice-r12-1" "2" node "mcr1058" "ice-r12-1" "3" node "mcr1059" "ice-r12-1" "4" node "mcr1060" "ice-r12-1" "5" node "mcr1061" "ice-r12-1" "6" node "mcr1062" "ice-r12-1" "7" node "mcr1063" "ice-r12-1" "8" node "mcr1064" "ice-r12-1" "9" node "mcr1065" "ice-r12-1" "10" # node "mcr1066" "ice-r12-2" "1" node "mcr1067" "ice-r12-2" "2" node "mcr1068" "ice-r12-2" "3" node "mcr1069" "ice-r12-2" "4" node "mcr1070" "ice-r12-2" "5" node "mcr1071" "ice-r12-2" "6" node "mcr1072" "ice-r12-2" "7" node "mcr1073" "ice-r12-2" "8" node "mcr1074" "ice-r12-2" "9" node "mcr1075" "ice-r12-2" "10" # node "mcr1076" "ice-r12-3" "1" node "mcr1077" "ice-r12-3" "2" node "mcr1078" "ice-r12-3" "3" node "mcr1079" "ice-r12-3" "4" node "mcr1080" "ice-r12-3" "5" node "mcr1081" "ice-r12-3" "6" node "mcr1082" "ice-r12-3" "7" node "mcr1083" "ice-r12-3" "8" node "mcr1084" "ice-r12-3" "9" node "mcr1085" "ice-r12-3" "10" # node "mcr1086" "ice-r12-4" "1" node "mcr1087" "ice-r12-4" "2" node "mcr1088" "ice-r12-4" "3" node "mcr1089" "ice-r12-4" "4" node "mcr1090" "ice-r12-4" "5" node "mcr1091" "ice-r12-4" "6" node "mcr1092" "ice-r12-4" "7" node "mcr1093" "ice-r12-4" "8" node "mcr1094" "ice-r12-4" "9" node "mcr1095" "ice-r12-4" "10" # node "mcr1096" "ice-r13-1" "1" node "mcr1097" "ice-r13-1" "2" node "mcr1098" "ice-r13-1" "3" node "mcr1099" "ice-r13-1" "4" node "mcr1100" "ice-r13-1" "5" node "mcr1101" "ice-r13-1" "6" # node "mcr1102" "ice-r13-2" "1" node "mcr1103" "ice-r13-2" "2" node "mcr1104" "ice-r13-2" "3" node "mcr1105" "ice-r13-2" "4" node "mcr1106" "ice-r13-2" "5" node "mcr1107" "ice-r13-2" "6" node "mcr1108" "ice-r13-2" "7" node "mcr1109" "ice-r13-2" "8" node "mcr1110" "ice-r13-2" "9" node "mcr1111" "ice-r13-2" "10" # node "mcr1112" "ice-r14-1" "1" node "mcr1113" "ice-r14-1" "2" node "mcr1114" "ice-r14-1" "3" node "mcr1115" "ice-r14-1" "4" node "mcr1116" "ice-r14-1" "5" node "mcr1117" "ice-r14-1" "6" node "mcr1118" "ice-r14-1" "7" node "mcr1119" "ice-r14-1" "8" node "mcr1120" "ice-r14-1" "9" node "mcr1121" "ice-r14-1" "10" # node "mcr1122" "ice-r14-2" "1" node "mcr1123" "ice-r14-2" "2" node "mcr1124" "ice-r14-2" "3" node "mcr1125" "ice-r14-2" "4" node "mcr1126" "ice-r14-2" "5" node "mcr1127" "ice-r14-2" "6" node "mcr1128" "ice-r14-2" "7" node "mcr1129" "ice-r14-2" "8" node "mcr1130" "ice-r14-2" "9" node "mcr1131" "ice-r14-2" "10" # node "mcr1132" "ice-r14-3" "1" node "mcr1133" "ice-r14-3" "2" node "mcr1134" "ice-r14-3" "3" node "mcr1135" "ice-r14-3" "4" node "mcr1136" "ice-r14-3" "5" node "mcr1137" "ice-r14-3" "6" node "mcr1138" "ice-r14-3" "7" node "mcr1139" "ice-r14-3" "8" node "mcr1140" "ice-r14-3" "9" node "mcr1141" "ice-r14-3" "10" # node "mcr1142" "ice-r14-4" "1" node "mcr1143" "ice-r14-4" "2" node "mcr1144" "ice-r14-4" "3" node "mcr1145" "ice-r14-4" "4" node "mcr1146" "ice-r14-4" "5" node "mcr1147" "ice-r14-4" "6" node "mcr1148" "ice-r14-4" "7" node "mcr1149" "ice-r14-4" "8" node "mcr1150" "ice-r14-4" "9" node "mcr1151" "ice-r14-4" "10" powerman-2.4.4/t/etc/redfishpower-parents-2-levels.dev000066400000000000000000000026141467035776500227200ustar00rootroot00000000000000# Variant of redfishpower-cray-r272z30.dev that covers use of setplugs # configuration with a parent. Node0 is the parent of Node[1-15] specification "redfishpower-parents-2-levels" { timeout 60 script login { expect "redfishpower> " send "auth USER:PASS\n" expect "redfishpower> " send "setheader Content-Type:application/json\n" expect "redfishpower> " send "setplugs Node0 0\n" expect "redfishpower> " send "setplugs Node[1-15] [1-15] Node0\n" expect "redfishpower> " send "setstatpath redfish/v1/Systems/Self\n" expect "redfishpower> " send "setonpath redfish/v1/Systems/Self/Actions/ComputerSystem.Reset {\"ResetType\":\"On\"}\n" expect "redfishpower> " send "setoffpath redfish/v1/Systems/Self/Actions/ComputerSystem.Reset {\"ResetType\":\"ForceOff\"}\n" expect "redfishpower> " send "setcyclepath redfish/v1/Systems/Self/Actions/ComputerSystem.Reset {\"ResetType\":\"ForceRestart\"}\n" expect "redfishpower> " send "settimeout 60\n" expect "redfishpower> " } script logout { send "quit\n" } script status_all { send "stat\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setplugstate $1 $2 on="^on\n" off="^off\n" } expect "redfishpower> " } script on_ranged { send "on %s\n" expect "redfishpower> " } script off_ranged { send "off %s\n" expect "redfishpower> " } script cycle_ranged { send "cycle %s\n" expect "redfishpower> " } } powerman-2.4.4/t/etc/redfishpower-parents-3-levels.dev000066400000000000000000000033251467035776500227210ustar00rootroot00000000000000# Variant of redfishpower-cray-r272z30.dev that covers use of setplugs # configuration with parents. # Node0 is the parent of Node[1-3] # Node1 is the parent of Node[4-7] # Node2 is the parent of Node[8-11] # Node3 is the parent of Node[12-15] specification "redfishpower-parents-3-levels" { timeout 60 script login { expect "redfishpower> " send "auth USER:PASS\n" expect "redfishpower> " send "setheader Content-Type:application/json\n" expect "redfishpower> " send "setplugs Node0 0\n" expect "redfishpower> " send "setplugs Node[1-3] [1-3] Node0\n" expect "redfishpower> " send "setplugs Node[4-7] [4-7] Node1\n" expect "redfishpower> " send "setplugs Node[8-11] [8-11] Node2\n" expect "redfishpower> " send "setplugs Node[12-15] [12-15] Node3\n" expect "redfishpower> " send "setstatpath redfish/v1/Systems/Self\n" expect "redfishpower> " send "setonpath redfish/v1/Systems/Self/Actions/ComputerSystem.Reset {\"ResetType\":\"On\"}\n" expect "redfishpower> " send "setoffpath redfish/v1/Systems/Self/Actions/ComputerSystem.Reset {\"ResetType\":\"ForceOff\"}\n" expect "redfishpower> " send "setcyclepath redfish/v1/Systems/Self/Actions/ComputerSystem.Reset {\"ResetType\":\"ForceRestart\"}\n" expect "redfishpower> " send "settimeout 60\n" expect "redfishpower> " } script logout { send "quit\n" } script status_all { send "stat\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setplugstate $1 $2 on="^on\n" off="^off\n" } expect "redfishpower> " } script on_ranged { send "on %s\n" expect "redfishpower> " } script off_ranged { send "off %s\n" expect "redfishpower> " } script cycle_ranged { send "cycle %s\n" expect "redfishpower> " } } powerman-2.4.4/t/etc/redfishpower-plugsub-blades.dev000066400000000000000000000026311467035776500225250ustar00rootroot00000000000000# Variant of redfishpower-cray-r272z30.dev that covers use of plug # substitution and the assumption of blades. # # Notes: # - hypothetical blades go through Node0 # - for easier grepping in tests, simplify paths specification "redfishpower-plugsub-blades" { timeout 60 script login { expect "redfishpower> " send "auth USER:PASS\n" expect "redfishpower> " send "setheader Content-Type:application/json\n" expect "redfishpower> " send "setplugs Node[0-15] [0-15]\n" expect "redfishpower> " send "setplugs Blade[0-3] 0\n" expect "redfishpower> " send "setstatpath redfish/Default-{{plug}}/Stat\n" expect "redfishpower> " send "setonpath redfish/Default-{{plug}}/Reset {\"ResetType\":\"On\"}\n" expect "redfishpower> " send "setoffpath redfish/Default-{{plug}}/Reset {\"ResetType\":\"ForceOff\"}\n" expect "redfishpower> " send "setcyclepath redfish/Default-{{plug}}/Reset {\"ResetType\":\"ForceRestart\"}\n" expect "redfishpower> " send "settimeout 60\n" expect "redfishpower> " } script logout { send "quit\n" } script status_all { send "stat\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setplugstate $1 $2 on="^on\n" off="^off\n" } expect "redfishpower> " } script on_ranged { send "on %s\n" expect "redfishpower> " } script off_ranged { send "off %s\n" expect "redfishpower> " } script cycle_ranged { send "cycle %s\n" expect "redfishpower> " } } powerman-2.4.4/t/etc/redfishpower-plugsub.dev000066400000000000000000000035211467035776500212740ustar00rootroot00000000000000# Variant of redfishpower-cray-r272z30.dev that covers use of plug # substitution. # # Notes: # - for easier grepping in tests, simplify paths # - different paths for different chunks of nodes/plugs # - no plug specific paths set for Node[8-15], will use defaults # set via setstatpath, setonpath, etc. specification "redfishpower-plugsub" { timeout 60 script login { expect "redfishpower> " send "auth USER:PASS\n" expect "redfishpower> " send "setheader Content-Type:application/json\n" expect "redfishpower> " send "setplugs Node[0-15] [0-15]\n" expect "redfishpower> " send "setpath Node[0-7] stat redfish/Group0\n" expect "redfishpower> " send "setpath Node[0-7] on redfish/Group0-{{plug}}/Reset {\"ResetType\":\"On\"}\n" expect "redfishpower> " send "setpath Node[0-7] off redfish/Group0-{{plug}}/Reset {\"ResetType\":\"ForceOff\"}\n" expect "redfishpower> " send "setpath Node[0-7] cycle redfish/Group0-{{plug}}/Reset {\"ResetType\":\"ForceRestart\"}\n" expect "redfishpower> " send "setstatpath redfish/Default\n" expect "redfishpower> " send "setonpath redfish/Default-{{plug}}/Reset {\"ResetType\":\"On\"}\n" expect "redfishpower> " send "setoffpath redfish/Default-{{plug}}/Reset {\"ResetType\":\"ForceOff\"}\n" expect "redfishpower> " send "setcyclepath redfish/Default-{{plug}}/Reset {\"ResetType\":\"ForceRestart\"}\n" expect "redfishpower> " send "settimeout 60\n" expect "redfishpower> " } script logout { send "quit\n" } script status_all { send "stat\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setplugstate $1 $2 on="^on\n" off="^off\n" } expect "redfishpower> " } script on_ranged { send "on %s\n" expect "redfishpower> " } script off_ranged { send "off %s\n" expect "redfishpower> " } script cycle_ranged { send "cycle %s\n" expect "redfishpower> " } } powerman-2.4.4/t/etc/redfishpower-setpath.dev000066400000000000000000000042751467035776500212720ustar00rootroot00000000000000# Variant of redfishpower-cray-r272z30.dev that covers use of setplugs # and setpath configuration # # Notes: # - for easier grepping in tests, simplify paths # - different paths for different chunks of nodes/plugs # - no plug specific paths set for Node[10-15], will use defaults # set via setstatpath, setonpath, etc. specification "redfishpower-setpath" { timeout 60 script login { expect "redfishpower> " send "auth USER:PASS\n" expect "redfishpower> " send "setheader Content-Type:application/json\n" expect "redfishpower> " send "setplugs Node[0-15] [0-15]\n" expect "redfishpower> " send "setpath Node[0-4] stat redfish/Group0\n" expect "redfishpower> " send "setpath Node[0-4] on redfish/Group0/Reset {\"ResetType\":\"On\"}\n" expect "redfishpower> " send "setpath Node[0-4] off redfish/Group0/Reset {\"ResetType\":\"ForceOff\"}\n" expect "redfishpower> " send "setpath Node[0-4] cycle redfish/Group0/Reset {\"ResetType\":\"ForceRestart\"}\n" expect "redfishpower> " send "setpath Node[5-9] stat redfish/Group1\n" expect "redfishpower> " send "setpath Node[5-9] on redfish/Group1/Reset {\"ResetType\":\"On\"}\n" expect "redfishpower> " send "setpath Node[5-9] off redfish/Group1/Reset {\"ResetType\":\"ForceOff\"}\n" expect "redfishpower> " send "setpath Node[5-9] cycle redfish/Group1/Reset {\"ResetType\":\"ForceRestart\"}\n" expect "redfishpower> " send "setstatpath redfish/Default\n" expect "redfishpower> " send "setonpath redfish/Default/Reset {\"ResetType\":\"On\"}\n" expect "redfishpower> " send "setoffpath redfish/Default/Reset {\"ResetType\":\"ForceOff\"}\n" expect "redfishpower> " send "setcyclepath redfish/Default/Reset {\"ResetType\":\"ForceRestart\"}\n" expect "redfishpower> " send "settimeout 60\n" expect "redfishpower> " } script logout { send "quit\n" } script status_all { send "stat\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setplugstate $1 $2 on="^on\n" off="^off\n" } expect "redfishpower> " } script on_ranged { send "on %s\n" expect "redfishpower> " } script off_ranged { send "off %s\n" expect "redfishpower> " } script cycle_ranged { send "cycle %s\n" expect "redfishpower> " } } powerman-2.4.4/t/etc/redfishpower-setplugs.dev000066400000000000000000000024261467035776500214640ustar00rootroot00000000000000# Variant of redfishpower-cray-r272z30.dev that covers use of setplugs # configuration specification "redfishpower-setplugs" { timeout 60 script login { expect "redfishpower> " send "auth USER:PASS\n" expect "redfishpower> " send "setheader Content-Type:application/json\n" expect "redfishpower> " send "setplugs Node[0-15] [0-15]\n" expect "redfishpower> " send "setstatpath redfish/v1/Systems/Self\n" expect "redfishpower> " send "setonpath redfish/v1/Systems/Self/Actions/ComputerSystem.Reset {\"ResetType\":\"On\"}\n" expect "redfishpower> " send "setoffpath redfish/v1/Systems/Self/Actions/ComputerSystem.Reset {\"ResetType\":\"ForceOff\"}\n" expect "redfishpower> " send "setcyclepath redfish/v1/Systems/Self/Actions/ComputerSystem.Reset {\"ResetType\":\"ForceRestart\"}\n" expect "redfishpower> " send "settimeout 60\n" expect "redfishpower> " } script logout { send "quit\n" } script status_all { send "stat\n" foreachnode { expect "([^\n:]+): ([^\n]+\n)" setplugstate $1 $2 on="^on\n" off="^off\n" } expect "redfishpower> " } script on_ranged { send "on %s\n" expect "redfishpower> " } script off_ranged { send "off %s\n" expect "redfishpower> " } script cycle_ranged { send "cycle %s\n" expect "redfishpower> " } } powerman-2.4.4/t/etc/sierra_plugs.conf000066400000000000000000002022741467035776500177700ustar00rootroot00000000000000# plug portion of sierra powerman.conf, modified to work in test harness # IPMI Control node "sierra[0,2-143]" "ipmi0" "psierra[0,2-143]" node "sierra[144-287]" "ipmi1" "psierra[144-287]" node "sierra[288-431]" "ipmi2" "psierra[288-431]" node "sierra[432-575]" "ipmi3" "psierra[432-575]" node "sierra[576-719]" "ipmi4" "psierra[576-719]" node "sierra[720-863]" "ipmi5" "psierra[720-863]" node "sierra[864-1007]" "ipmi6" "psierra[864-1007]" node "sierra[1008-1151]" "ipmi7" "psierra[1008-1151]" node "sierra[1152-1295]" "ipmi8" "psierra[1152-1295]" node "sierra[1296-1439]" "ipmi9" "psierra[1296-1439]" node "sierra[1440-1583]" "ipmi10" "psierra[1440-1583]" node "sierra[1584-1727]" "ipmi11" "psierra[1584-1727]" node "sierra[1728-1871]" "ipmi12" "psierra[1728-1871]" node "sierra[1872-1943]" "ipmi13" "psierra[1872-1943]" # PDU Chassis Control # Rack 1 LSM,RPS,GW nodes node "pdu-sierra1a" "pdu1" "47" #sierra1ps1 node "pdu-sierra0" "pdu1" "46" #sierra0 node "pdu-sierra1b" "pdu1" "44" #sierra1ps2 node "pdu-sierra2" "pdu1" "43" #sierra2 node "pdu-sierra3" "pdu1" "42" #sierra3 node "pdu-sierra4" "pdu1" "41" #sierra4 node "pdu-sierra7a" "pdu1" "40" #sierra7ps1 node "pdu-sierra5" "pdu1" "39" #sierra5 node "pdu-sierra7b" "pdu1" "37" #sierra7ps2 node "pdu-sierra6" "pdu1" "36" #sierra6 node "pdu-sierra8" "pdu1" "34" #sierra8 node "pdu-sierra9" "pdu1" "32" #sierra9 node "pdu-sierra10" "pdu1" "31" #sierra10 node "pdu-sierra11" "pdu1" "29" #sierra11 # Rack 1 Compute nodes node "chassis1a" "pdu1" "23" #sierra[12,14] node "chassis1b" "pdu1" "20" #sierra[13,15] node "chassis2a" "pdu1" "18" #sierra[16,18] node "chassis2b" "pdu1" "15" #sierra[17,19] node "chassis3a" "pdu1" "13" #sierra[20,22] node "chassis3b" "pdu1" "10" #sierra[21,23] node "chassis4a" "pdu1" "12" #sierra[24,26] node "chassis4b" "pdu1" "9" #sierra[25,27] node "chassis5a" "pdu1" "5" #sierra[28,30] node "chassis5b" "pdu1" "2" #sierra[29,31] node "chassis6a" "pdu1" "4" #sierra[32,34] node "chassis6b" "pdu1" "1" #sierra[33,35] # Rack 2 node "chassis7a" "pdu2" "48" #sierra[36,38] node "chassis7b" "pdu2" "45" #sierra[37,39] node "chassis8a" "pdu2" "47" #sierra[40,42] node "chassis8b" "pdu2" "44" #sierra[41,43] node "chassis9a" "pdu2" "43" #sierra[44,46] node "chassis9b" "pdu2" "40" #sierra[45,47] node "chassis10a" "pdu2" "41" #sierra[48,50] node "chassis10b" "pdu2" "38" #sierra[49,51] node "chassis11a" "pdu2" "39" #sierra[52,54] node "chassis11b" "pdu2" "36" #sierra[53,55] node "chassis12a" "pdu2" "37" #sierra[56,58] node "chassis12b" "pdu2" "34" #sierra[57,59] node "chassis13a" "pdu2" "30" #sierra[60,62] node "chassis13b" "pdu2" "27" #sierra[61,63] node "chassis14a" "pdu2" "29" #sierra[64,66] node "chassis14b" "pdu2" "26" #sierra[65,67] node "chassis15a" "pdu2" "28" #sierra[68,70] node "chassis15b" "pdu2" "25" #sierra[69,71] node "chassis16a" "pdu2" "23" #sierra[72,74] node "chassis16b" "pdu2" "20" #sierra[73,75] node "chassis17a" "pdu2" "19" #sierra[76,78] node "chassis17b" "pdu2" "16" #sierra[77,79] node "chassis18a" "pdu2" "18" #sierra[80,82] node "chassis18b" "pdu2" "15" #sierra[81,83] node "chassis19a" "pdu2" "13" #sierra[84,86] node "chassis19b" "pdu2" "10" #sierra[85,87] node "chassis20a" "pdu2" "12" #sierra[88,90] node "chassis20b" "pdu2" "9" #sierra[89,91] node "chassis21a" "pdu2" "11" #sierra[92,94] node "chassis21b" "pdu2" "8" #sierra[93,95] node "chassis22a" "pdu2" "6" #sierra[96,98] node "chassis22b" "pdu2" "3" #sierra[97,99] node "chassis23a" "pdu2" "5" #sierra[100,102] node "chassis23b" "pdu2" "2" #sierra[101,103] node "chassis24a" "pdu2" "4" #sierra[104,106] node "chassis24b" "pdu2" "1" #sierra[105,107] # Rack 3 node "chassis25a" "pdu3" "48" #sierra[108,110] node "chassis25b" "pdu3" "45" #sierra[109,111] node "chassis26a" "pdu3" "47" node "chassis26b" "pdu3" "44" node "chassis27a" "pdu3" "43" node "chassis27b" "pdu3" "40" node "chassis28a" "pdu3" "41" node "chassis28b" "pdu3" "38" node "chassis29a" "pdu3" "39" node "chassis29b" "pdu3" "36" node "chassis30a" "pdu3" "37" node "chassis30b" "pdu3" "34" node "chassis31a" "pdu3" "30" node "chassis31b" "pdu3" "27" node "chassis32a" "pdu3" "29" node "chassis32b" "pdu3" "26" node "chassis33a" "pdu3" "28" node "chassis33b" "pdu3" "25" node "chassis34a" "pdu3" "23" node "chassis34b" "pdu3" "20" node "chassis35a" "pdu3" "19" node "chassis35b" "pdu3" "16" node "chassis36a" "pdu3" "18" node "chassis36b" "pdu3" "15" node "chassis37a" "pdu3" "13" node "chassis37b" "pdu3" "10" node "chassis38a" "pdu3" "12" node "chassis38b" "pdu3" "9" node "chassis39a" "pdu3" "11" node "chassis39b" "pdu3" "8" node "chassis40a" "pdu3" "6" node "chassis40b" "pdu3" "3" node "chassis41a" "pdu3" "5" node "chassis41b" "pdu3" "2" node "chassis42a" "pdu3" "4" #sierra[176,178] node "chassis42b" "pdu3" "1" #sierra[177,179] # Rack 4 node "chassis43a" "pdu4" "48" #sierra[180,182] node "chassis43b" "pdu4" "45" #sierra[181,183] node "chassis44a" "pdu4" "47" node "chassis44b" "pdu4" "44" node "chassis45a" "pdu4" "43" node "chassis45b" "pdu4" "40" node "chassis46a" "pdu4" "41" node "chassis46b" "pdu4" "38" node "chassis47a" "pdu4" "39" node "chassis47b" "pdu4" "36" node "chassis48a" "pdu4" "37" node "chassis48b" "pdu4" "34" node "chassis49a" "pdu4" "30" node "chassis49b" "pdu4" "27" node "chassis50a" "pdu4" "29" node "chassis50b" "pdu4" "26" node "chassis51a" "pdu4" "28" node "chassis51b" "pdu4" "25" node "chassis52a" "pdu4" "23" node "chassis52b" "pdu4" "20" node "chassis53a" "pdu4" "19" node "chassis53b" "pdu4" "16" node "chassis54a" "pdu4" "18" node "chassis54b" "pdu4" "15" node "chassis55a" "pdu4" "13" node "chassis55b" "pdu4" "10" node "chassis56a" "pdu4" "12" node "chassis56b" "pdu4" "9" node "chassis57a" "pdu4" "11" node "chassis57b" "pdu4" "8" node "chassis58a" "pdu4" "6" node "chassis58b" "pdu4" "3" node "chassis59a" "pdu4" "5" node "chassis59b" "pdu4" "2" node "chassis60a" "pdu4" "4" #sierra[248,250] node "chassis60b" "pdu4" "1" #sierra[249,251] # Rack 5 node "chassis61a" "pdu5" "48" #sierra[252,254] node "chassis61b" "pdu5" "45" #sierra[253,255] node "chassis62a" "pdu5" "47" node "chassis62b" "pdu5" "44" node "chassis63a" "pdu5" "43" node "chassis63b" "pdu5" "40" node "chassis64a" "pdu5" "41" node "chassis64b" "pdu5" "38" node "chassis65a" "pdu5" "39" node "chassis65b" "pdu5" "36" node "chassis66a" "pdu5" "37" node "chassis66b" "pdu5" "34" node "chassis67a" "pdu5" "30" node "chassis67b" "pdu5" "27" node "chassis68a" "pdu5" "29" node "chassis68b" "pdu5" "26" node "chassis69a" "pdu5" "28" node "chassis69b" "pdu5" "25" node "chassis70a" "pdu5" "23" node "chassis70b" "pdu5" "20" node "chassis71a" "pdu5" "19" node "chassis71b" "pdu5" "16" node "chassis72a" "pdu5" "18" node "chassis72b" "pdu5" "15" node "chassis73a" "pdu5" "13" node "chassis73b" "pdu5" "10" node "chassis74a" "pdu5" "12" node "chassis74b" "pdu5" "9" node "chassis75a" "pdu5" "11" node "chassis75b" "pdu5" "8" node "chassis76a" "pdu5" "6" node "chassis76b" "pdu5" "3" node "chassis77a" "pdu5" "5" node "chassis77b" "pdu5" "2" node "chassis78a" "pdu5" "4" #sierra[320,322] node "chassis78b" "pdu5" "1" #sierra[321,323] # Rack 6 LSM,RPS,GW nodes node "pdu-sierra325a" "pdu6" "47" #sierra325ps1 node "pdu-sierra324" "pdu6" "46" #sierra324 node "pdu-sierra325b" "pdu6" "44" #sierra325ps2 node "pdu-sierra326" "pdu6" "43" #sierra326 node "pdu-sierra327" "pdu6" "42" #sierra327 node "pdu-sierra328" "pdu6" "41" #sierra328 node "pdu-sierra331a" "pdu6" "40" #sierra331ps1 node "pdu-sierra329" "pdu6" "39" #sierra329 node "pdu-sierra331b" "pdu6" "37" #sierra331ps2 node "pdu-sierra330" "pdu6" "36" #sierra330 node "pdu-sierra332" "pdu6" "34" #sierra332 node "pdu-sierra333" "pdu6" "32" #sierra333 node "pdu-sierra334" "pdu6" "31" #sierra334 node "pdu-sierra335" "pdu6" "29" #sierra335 # Rack 6 Compute nodes node "chassis79a" "pdu6" "23" #sierra[336,338] node "chassis79b" "pdu6" "20" #sierra[337,339] node "chassis80a" "pdu6" "18" node "chassis80b" "pdu6" "15" node "chassis81a" "pdu6" "13" node "chassis81b" "pdu6" "10" node "chassis82a" "pdu6" "12" node "chassis82b" "pdu6" "9" node "chassis83a" "pdu6" "5" node "chassis83b" "pdu6" "2" node "chassis84a" "pdu6" "4" #sierra[356,358] node "chassis84b" "pdu6" "1" #sierra[357,359] # Rack 7 node "chassis85a" "pdu7" "48" #sierra[360,362] node "chassis85b" "pdu7" "45" #sierra[361,363] node "chassis86a" "pdu7" "47" node "chassis86b" "pdu7" "44" node "chassis87a" "pdu7" "43" node "chassis87b" "pdu7" "40" node "chassis88a" "pdu7" "41" node "chassis88b" "pdu7" "38" node "chassis89a" "pdu7" "39" node "chassis89b" "pdu7" "36" node "chassis90a" "pdu7" "37" node "chassis90b" "pdu7" "34" node "chassis91a" "pdu7" "30" node "chassis91b" "pdu7" "27" node "chassis92a" "pdu7" "29" node "chassis92b" "pdu7" "26" node "chassis93a" "pdu7" "28" node "chassis93b" "pdu7" "25" node "chassis94a" "pdu7" "23" node "chassis94b" "pdu7" "20" node "chassis95a" "pdu7" "19" node "chassis95b" "pdu7" "16" node "chassis96a" "pdu7" "18" node "chassis96b" "pdu7" "15" node "chassis97a" "pdu7" "13" node "chassis97b" "pdu7" "10" node "chassis98a" "pdu7" "12" node "chassis98b" "pdu7" "9" node "chassis99a" "pdu7" "11" node "chassis99b" "pdu7" "8" node "chassis100a" "pdu7" "6" node "chassis100b" "pdu7" "3" node "chassis101a" "pdu7" "5" node "chassis101b" "pdu7" "2" node "chassis102a" "pdu7" "4" #sierra[428,430] node "chassis102b" "pdu7" "1" #sierra[429,431] # Rack 8 node "chassis103a" "pdu8" "48" #sierra[432,434] node "chassis103b" "pdu8" "45" #sierra[433,435] node "chassis104a" "pdu8" "47" node "chassis104b" "pdu8" "44" node "chassis105a" "pdu8" "43" node "chassis105b" "pdu8" "40" node "chassis106a" "pdu8" "41" node "chassis106b" "pdu8" "38" node "chassis107a" "pdu8" "39" node "chassis107b" "pdu8" "36" node "chassis108a" "pdu8" "37" node "chassis108b" "pdu8" "34" node "chassis109a" "pdu8" "30" node "chassis109b" "pdu8" "27" node "chassis110a" "pdu8" "29" node "chassis110b" "pdu8" "26" node "chassis111a" "pdu8" "28" node "chassis111b" "pdu8" "25" node "chassis112a" "pdu8" "23" node "chassis112b" "pdu8" "20" node "chassis113a" "pdu8" "19" node "chassis113b" "pdu8" "16" node "chassis114a" "pdu8" "18" node "chassis114b" "pdu8" "15" node "chassis115a" "pdu8" "13" node "chassis115b" "pdu8" "10" node "chassis116a" "pdu8" "12" node "chassis116b" "pdu8" "9" node "chassis117a" "pdu8" "11" node "chassis117b" "pdu8" "8" node "chassis118a" "pdu8" "6" node "chassis118b" "pdu8" "3" node "chassis119a" "pdu8" "5" node "chassis119b" "pdu8" "2" node "chassis120a" "pdu8" "4" #sierra[500,502] node "chassis120b" "pdu8" "1" #sierra[501,503] # Rack 9 node "chassis121a" "pdu9" "48" #sierra[504,506] node "chassis121b" "pdu9" "45" #sierra[505,507] node "chassis122a" "pdu9" "47" node "chassis122b" "pdu9" "44" node "chassis123a" "pdu9" "43" node "chassis123b" "pdu9" "40" node "chassis124a" "pdu9" "41" node "chassis124b" "pdu9" "38" node "chassis125a" "pdu9" "39" node "chassis125b" "pdu9" "36" node "chassis126a" "pdu9" "37" node "chassis126b" "pdu9" "34" node "chassis127a" "pdu9" "30" node "chassis127b" "pdu9" "27" node "chassis128a" "pdu9" "29" node "chassis128b" "pdu9" "26" node "chassis129a" "pdu9" "28" node "chassis129b" "pdu9" "25" node "chassis130a" "pdu9" "23" node "chassis130b" "pdu9" "20" node "chassis131a" "pdu9" "19" node "chassis131b" "pdu9" "16" node "chassis132a" "pdu9" "18" node "chassis132b" "pdu9" "15" node "chassis133a" "pdu9" "13" node "chassis133b" "pdu9" "10" node "chassis134a" "pdu9" "12" node "chassis134b" "pdu9" "9" node "chassis135a" "pdu9" "11" node "chassis135b" "pdu9" "8" node "chassis136a" "pdu9" "6" node "chassis136b" "pdu9" "3" node "chassis137a" "pdu9" "5" node "chassis137b" "pdu9" "2" node "chassis138a" "pdu9" "4" #sierra[572,574] node "chassis138b" "pdu9" "1" #sierra[573,575] # Rack 10 node "chassis139a" "pdu10" "48" #sierra[576,578] node "chassis139b" "pdu10" "45" #sierra[577,579] node "chassis140a" "pdu10" "47" node "chassis140b" "pdu10" "44" node "chassis141a" "pdu10" "43" node "chassis141b" "pdu10" "40" node "chassis142a" "pdu10" "41" node "chassis142b" "pdu10" "38" node "chassis143a" "pdu10" "39" node "chassis143b" "pdu10" "36" node "chassis144a" "pdu10" "37" node "chassis144b" "pdu10" "34" node "chassis145a" "pdu10" "30" node "chassis145b" "pdu10" "27" node "chassis146a" "pdu10" "29" node "chassis146b" "pdu10" "26" node "chassis147a" "pdu10" "28" node "chassis147b" "pdu10" "25" node "chassis148a" "pdu10" "23" node "chassis148b" "pdu10" "20" node "chassis149a" "pdu10" "19" node "chassis149b" "pdu10" "16" node "chassis150a" "pdu10" "18" node "chassis150b" "pdu10" "15" node "chassis151a" "pdu10" "13" node "chassis151b" "pdu10" "10" node "chassis152a" "pdu10" "12" node "chassis152b" "pdu10" "9" node "chassis153a" "pdu10" "11" node "chassis153b" "pdu10" "8" node "chassis154a" "pdu10" "6" node "chassis154b" "pdu10" "3" node "chassis155a" "pdu10" "5" node "chassis155b" "pdu10" "2" node "chassis156a" "pdu10" "4" #sierra[644,646] node "chassis156b" "pdu10" "1" #sierra[645,647] # Rack 11 LSM,RPS,GW nodes node "pdu-sierra649a" "pdu11" "47" #sierra649ps1 node "pdu-sierra648" "pdu11" "46" #sierra648 node "pdu-sierra649b" "pdu11" "44" #sierra649ps2 node "pdu-sierra650" "pdu11" "43" #sierra650 node "pdu-sierra651" "pdu11" "42" #sierra651 node "pdu-sierra652" "pdu11" "41" #sierra652 node "pdu-sierra655a" "pdu11" "40" #sierra655ps1 node "pdu-sierra653" "pdu11" "39" #sierra653 node "pdu-sierra655b" "pdu11" "37" #sierra655ps2 node "pdu-sierra654" "pdu11" "36" #sierra654 node "pdu-sierra656" "pdu11" "34" #sierra656 node "pdu-sierra657" "pdu11" "32" #sierra657 node "pdu-sierra658" "pdu11" "31" #sierra658 node "pdu-sierra659" "pdu11" "29" #sierra659 # Rack 11 Compute nodes node "chassis157a" "pdu11" "23" #sierra[660,662] node "chassis157b" "pdu11" "20" #sierra[661,663] node "chassis158a" "pdu11" "18" node "chassis158b" "pdu11" "15" node "chassis159a" "pdu11" "13" node "chassis159b" "pdu11" "10" node "chassis160a" "pdu11" "12" node "chassis160b" "pdu11" "9" node "chassis161a" "pdu11" "5" node "chassis161b" "pdu11" "2" node "chassis162a" "pdu11" "4" #sierra[680,682] node "chassis162b" "pdu11" "1" #sierra[681,683] # Rack 12 node "chassis163a" "pdu12" "48" #sierra[684,686] node "chassis163b" "pdu12" "45" #sierra[685,687] node "chassis164a" "pdu12" "47" node "chassis164b" "pdu12" "44" node "chassis165a" "pdu12" "43" node "chassis165b" "pdu12" "40" node "chassis166a" "pdu12" "41" node "chassis166b" "pdu12" "38" node "chassis167a" "pdu12" "39" node "chassis167b" "pdu12" "36" node "chassis168a" "pdu12" "37" node "chassis168b" "pdu12" "34" node "chassis169a" "pdu12" "30" node "chassis169b" "pdu12" "27" node "chassis170a" "pdu12" "29" node "chassis170b" "pdu12" "26" node "chassis171a" "pdu12" "28" node "chassis171b" "pdu12" "25" node "chassis172a" "pdu12" "23" node "chassis172b" "pdu12" "20" node "chassis173a" "pdu12" "19" node "chassis173b" "pdu12" "16" node "chassis174a" "pdu12" "18" node "chassis174b" "pdu12" "15" node "chassis175a" "pdu12" "13" node "chassis175b" "pdu12" "10" node "chassis176a" "pdu12" "12" node "chassis176b" "pdu12" "9" node "chassis177a" "pdu12" "11" node "chassis177b" "pdu12" "8" node "chassis178a" "pdu12" "6" node "chassis178b" "pdu12" "3" node "chassis179a" "pdu12" "5" node "chassis179b" "pdu12" "2" node "chassis180a" "pdu12" "4" #sierra[752,754] node "chassis180b" "pdu12" "1" #sierra[753,755] # Rack 13 node "chassis181a" "pdu13" "48" #sierra[756,758] node "chassis181b" "pdu13" "45" #sierra[757,759] node "chassis182a" "pdu13" "47" node "chassis182b" "pdu13" "44" node "chassis183a" "pdu13" "43" node "chassis183b" "pdu13" "40" node "chassis184a" "pdu13" "41" node "chassis184b" "pdu13" "38" node "chassis185a" "pdu13" "39" node "chassis185b" "pdu13" "36" node "chassis186a" "pdu13" "37" node "chassis186b" "pdu13" "34" node "cyclades22b" "pdu13" "33" node "chassis187a" "pdu13" "30" node "chassis187b" "pdu13" "27" node "chassis188a" "pdu13" "29" node "chassis188b" "pdu13" "26" node "chassis189a" "pdu13" "28" node "chassis189b" "pdu13" "25" node "chassis190a" "pdu13" "23" node "chassis190b" "pdu13" "20" node "chassis191a" "pdu13" "19" node "chassis191b" "pdu13" "16" node "chassis192a" "pdu13" "18" node "chassis192b" "pdu13" "15" node "chassis193a" "pdu13" "13" node "chassis193b" "pdu13" "10" node "chassis194a" "pdu13" "12" node "chassis194b" "pdu13" "9" node "chassis195a" "pdu13" "11" node "chassis195b" "pdu13" "8" node "chassis196a" "pdu13" "6" node "chassis196b" "pdu13" "3" node "chassis197a" "pdu13" "5" node "chassis197b" "pdu13" "2" node "chassis198a" "pdu13" "4" #sierra[824,826] node "chassis198b" "pdu13" "1" #sierra[825,827] # Rack 14 node "chassis199a" "pdu14" "48" #sierra[828,830] node "chassis199b" "pdu14" "45" #sierra[829,831] node "chassis200a" "pdu14" "47" node "chassis200b" "pdu14" "44" node "chassis201a" "pdu14" "43" node "chassis201b" "pdu14" "40" node "chassis202a" "pdu14" "41" node "chassis202b" "pdu14" "38" node "chassis203a" "pdu14" "39" node "chassis203b" "pdu14" "36" node "chassis204a" "pdu14" "37" node "chassis204b" "pdu14" "34" node "chassis205a" "pdu14" "30" node "chassis205b" "pdu14" "27" node "chassis206a" "pdu14" "29" node "chassis206b" "pdu14" "26" node "chassis207a" "pdu14" "28" node "chassis207b" "pdu14" "25" node "chassis208a" "pdu14" "23" node "chassis208b" "pdu14" "20" node "chassis209a" "pdu14" "19" node "chassis209b" "pdu14" "16" node "chassis210a" "pdu14" "18" node "chassis210b" "pdu14" "15" node "chassis211a" "pdu14" "13" node "chassis211b" "pdu14" "10" node "chassis212a" "pdu14" "12" node "chassis212b" "pdu14" "9" node "chassis213a" "pdu14" "11" node "chassis213b" "pdu14" "8" node "chassis214a" "pdu14" "6" node "chassis214b" "pdu14" "3" node "chassis215a" "pdu14" "5" node "chassis215b" "pdu14" "2" node "chassis216a" "pdu14" "4" #sierra[896,898] node "chassis216b" "pdu14" "1" #sierra[897,899] # Rack 15 node "chassis217a" "pdu15" "48" #sierra[900,902] node "chassis217b" "pdu15" "45" #sierra[901,903] node "chassis218a" "pdu15" "47" node "chassis218b" "pdu15" "44" node "chassis219a" "pdu15" "43" node "chassis219b" "pdu15" "40" node "chassis220a" "pdu15" "41" node "chassis220b" "pdu15" "38" node "chassis221a" "pdu15" "39" node "chassis221b" "pdu15" "36" node "chassis222a" "pdu15" "37" node "chassis222b" "pdu15" "34" node "chassis223a" "pdu15" "30" node "chassis223b" "pdu15" "27" node "chassis224a" "pdu15" "29" node "chassis224b" "pdu15" "26" node "chassis225a" "pdu15" "28" node "chassis225b" "pdu15" "25" node "chassis226a" "pdu15" "23" node "chassis226b" "pdu15" "20" node "chassis227a" "pdu15" "19" node "chassis227b" "pdu15" "16" node "chassis228a" "pdu15" "18" node "chassis228b" "pdu15" "15" node "chassis229a" "pdu15" "13" node "chassis229b" "pdu15" "10" node "chassis230a" "pdu15" "12" node "chassis230b" "pdu15" "9" node "chassis231a" "pdu15" "11" node "chassis231b" "pdu15" "8" node "chassis232a" "pdu15" "6" node "chassis232b" "pdu15" "3" node "chassis233a" "pdu15" "5" node "chassis233b" "pdu15" "2" node "chassis234a" "pdu15" "4" #sierra[968,970] node "chassis234b" "pdu15" "1" #sierra[969,971] # Racks 16 - 18 IBCORE switches # Rack 19 LSM,RPS,GW nodes node "pdu-sierra973a" "pdu19" "47" #sierra973ps1 node "pdu-sierra972" "pdu19" "46" #sierra972 node "pdu-sierra973b" "pdu19" "44" #sierra973ps2 node "pdu-sierra974" "pdu19" "43" #sierra974 node "pdu-sierra975" "pdu19" "42" #sierra975 node "pdu-sierra976" "pdu19" "41" #sierra976 node "pdu-sierra979a" "pdu19" "40" #sierra979ps1 node "pdu-sierra977" "pdu19" "39" #sierra977 node "pdu-sierra979b" "pdu19" "37" #sierra979ps2 node "pdu-sierra978" "pdu19" "36" #sierra978 node "pdu-sierra980" "pdu19" "34" #sierra980 node "pdu-sierra981" "pdu19" "32" #sierra981 node "pdu-sierra982" "pdu19" "31" #sierra982 node "pdu-sierra983" "pdu19" "29" #sierra983 # Rack 19 Compute nodes node "chassis235a" "pdu19" "23" #sierra[984,986] node "chassis235b" "pdu19" "20" #sierra[985,987] node "chassis236a" "pdu19" "18" node "chassis236b" "pdu19" "15" node "chassis237a" "pdu19" "13" node "chassis237b" "pdu19" "10" node "chassis238a" "pdu19" "12" node "chassis238b" "pdu19" "9" node "chassis239a" "pdu19" "5" node "chassis239b" "pdu19" "2" node "chassis240a" "pdu19" "4" #sierra[1004,1006] node "chassis240b" "pdu19" "1" #sierra[1005,1007] # Rack 20 node "chassis241a" "pdu20" "48" #sierra[1008,1010] node "chassis241b" "pdu20" "45" #sierra[1009,1011] node "chassis242a" "pdu20" "47" node "chassis242b" "pdu20" "44" node "chassis243a" "pdu20" "43" node "chassis243b" "pdu20" "40" node "chassis244a" "pdu20" "41" node "chassis244b" "pdu20" "38" node "chassis245a" "pdu20" "39" node "chassis245b" "pdu20" "36" node "chassis246a" "pdu20" "37" node "chassis246b" "pdu20" "34" node "chassis247a" "pdu20" "30" node "chassis247b" "pdu20" "27" node "chassis248a" "pdu20" "29" node "chassis248b" "pdu20" "26" node "chassis249a" "pdu20" "28" node "chassis249b" "pdu20" "25" node "chassis250a" "pdu20" "23" node "chassis250b" "pdu20" "20" node "chassis251a" "pdu20" "19" node "chassis251b" "pdu20" "16" node "chassis252a" "pdu20" "18" node "chassis252b" "pdu20" "15" node "chassis253a" "pdu20" "13" node "chassis253b" "pdu20" "10" node "chassis254a" "pdu20" "12" node "chassis254b" "pdu20" "9" node "chassis255a" "pdu20" "11" node "chassis255b" "pdu20" "8" node "chassis256a" "pdu20" "6" node "chassis256b" "pdu20" "3" node "chassis257a" "pdu20" "5" node "chassis257b" "pdu20" "2" node "chassis258a" "pdu20" "4" #sierra[1076,1078] node "chassis258b" "pdu20" "1" #sierra[1077,1079] # Rack 21 node "chassis259a" "pdu21" "48" #sierra[1080,1082] node "chassis259b" "pdu21" "45" #sierra[1081,1083] node "chassis260a" "pdu21" "47" node "chassis260b" "pdu21" "44" node "chassis261a" "pdu21" "43" node "chassis261b" "pdu21" "40" node "chassis262a" "pdu21" "41" node "chassis262b" "pdu21" "38" node "chassis263a" "pdu21" "39" node "chassis263b" "pdu21" "36" node "chassis264a" "pdu21" "37" node "chassis264b" "pdu21" "34" node "chassis265a" "pdu21" "30" node "chassis265b" "pdu21" "27" node "chassis266a" "pdu21" "29" node "chassis266b" "pdu21" "26" node "chassis267a" "pdu21" "28" node "chassis267b" "pdu21" "25" node "chassis268a" "pdu21" "23" node "chassis268b" "pdu21" "20" node "chassis269a" "pdu21" "19" node "chassis269b" "pdu21" "16" node "chassis270a" "pdu21" "18" node "chassis270b" "pdu21" "15" node "chassis271a" "pdu21" "13" node "chassis271b" "pdu21" "10" node "chassis272a" "pdu21" "12" node "chassis272b" "pdu21" "9" node "chassis273a" "pdu21" "11" node "chassis273b" "pdu21" "8" node "chassis274a" "pdu21" "6" node "chassis274b" "pdu21" "3" node "chassis275a" "pdu21" "5" node "chassis275b" "pdu21" "2" node "chassis276a" "pdu21" "4" #sierra[1148,1150] node "chassis276b" "pdu21" "1" #sierra[1149,1151] # Rack 22 node "chassis277a" "pdu22" "48" #sierra[1152,1154] node "chassis277b" "pdu22" "45" #sierra[1153,1155] node "chassis278a" "pdu22" "47" node "chassis278b" "pdu22" "44" node "chassis279a" "pdu22" "43" node "chassis279b" "pdu22" "40" node "chassis280a" "pdu22" "41" node "chassis280b" "pdu22" "38" node "chassis281a" "pdu22" "39" node "chassis281b" "pdu22" "36" node "chassis282a" "pdu22" "37" node "chassis282b" "pdu22" "34" node "chassis283a" "pdu22" "30" node "chassis283b" "pdu22" "27" node "chassis284a" "pdu22" "29" node "chassis284b" "pdu22" "26" node "chassis285a" "pdu22" "28" node "chassis285b" "pdu22" "25" node "chassis286a" "pdu22" "23" node "chassis286b" "pdu22" "20" node "chassis287a" "pdu22" "19" node "chassis287b" "pdu22" "16" node "chassis288a" "pdu22" "18" node "chassis288b" "pdu22" "15" node "chassis289a" "pdu22" "13" node "chassis289b" "pdu22" "10" node "chassis290a" "pdu22" "12" node "chassis290b" "pdu22" "9" node "chassis291a" "pdu22" "11" node "chassis291b" "pdu22" "8" node "chassis292a" "pdu22" "6" node "chassis292b" "pdu22" "3" node "chassis293a" "pdu22" "5" node "chassis293b" "pdu22" "2" node "chassis294a" "pdu22" "4" #sierra[1220,1222] node "chassis294b" "pdu22" "1" #sierra[1221,1223] # Rack 23 node "chassis295a" "pdu23" "48" #sierra[1224,1226] node "chassis295b" "pdu23" "45" #sierra[1225,1227] node "chassis296a" "pdu23" "47" node "chassis296b" "pdu23" "44" node "chassis297a" "pdu23" "43" node "chassis297b" "pdu23" "40" node "chassis298a" "pdu23" "41" node "chassis298b" "pdu23" "38" node "chassis299a" "pdu23" "39" node "chassis299b" "pdu23" "36" node "chassis300a" "pdu23" "37" node "chassis300b" "pdu23" "34" node "chassis301a" "pdu23" "30" node "chassis301b" "pdu23" "27" node "chassis302a" "pdu23" "29" node "chassis302b" "pdu23" "26" node "chassis303a" "pdu23" "28" node "chassis303b" "pdu23" "25" node "chassis304a" "pdu23" "23" node "chassis304b" "pdu23" "20" node "chassis305a" "pdu23" "19" node "chassis305b" "pdu23" "16" node "chassis306a" "pdu23" "18" node "chassis306b" "pdu23" "15" node "chassis307a" "pdu23" "13" node "chassis307b" "pdu23" "10" node "chassis308a" "pdu23" "12" node "chassis308b" "pdu23" "9" node "chassis309a" "pdu23" "11" node "chassis309b" "pdu23" "8" node "chassis310a" "pdu23" "6" node "chassis310b" "pdu23" "3" node "chassis311a" "pdu23" "5" node "chassis311b" "pdu23" "2" node "chassis312a" "pdu23" "4" #sierra[1292,1294] node "chassis312b" "pdu23" "1" #sierra[1293,1295] # Rack 24 LSM,RPS,GW nodes node "pdu-sierra1297a" "pdu24" "47" #sierra1297ps1 node "pdu-sierra1296" "pdu24" "46" #sierra1296 node "pdu-sierra1297b" "pdu24" "44" #sierra1297ps2 node "pdu-sierra1298" "pdu24" "43" #sierra1298 node "pdu-sierra1299" "pdu24" "42" #sierra1299 node "pdu-sierra1300" "pdu24" "41" #sierra1300 node "pdu-sierra1303a" "pdu24" "40" #sierra1303ps1 node "pdu-sierra1301" "pdu24" "39" #sierra1301 node "pdu-sierra1303b" "pdu24" "37" #sierra1303ps2 node "pdu-sierra1302" "pdu24" "36" #sierra1302 node "pdu-sierra1304" "pdu24" "34" #sierra1304 node "pdu-sierra1305" "pdu24" "32" #sierra1305 node "pdu-sierra1306" "pdu24" "31" #sierra1306 node "pdu-sierra1307" "pdu24" "29" #sierra1307 # Rack 24 Compute nodes node "chassis313a" "pdu24" "23" #sierra[1308,1310] node "chassis313b" "pdu24" "20" #sierra[1309,1311] node "chassis314a" "pdu24" "18" node "chassis314b" "pdu24" "15" node "chassis315a" "pdu24" "13" node "chassis315b" "pdu24" "10" node "chassis316a" "pdu24" "12" node "chassis316b" "pdu24" "9" node "chassis317a" "pdu24" "5" node "chassis317b" "pdu24" "2" node "chassis318a" "pdu24" "4" #sierra[1328,1330] node "chassis318b" "pdu24" "1" #sierra[1329,1331] # Rack 25 node "chassis319a" "pdu25" "48" #sierra[1332,1334] node "chassis319b" "pdu25" "45" #sierra[1333,1335] node "chassis320a" "pdu25" "47" node "chassis320b" "pdu25" "44" node "chassis321a" "pdu25" "43" node "chassis321b" "pdu25" "40" node "chassis322a" "pdu25" "41" node "chassis322b" "pdu25" "38" node "chassis323a" "pdu25" "39" node "chassis323b" "pdu25" "36" node "chassis324a" "pdu25" "37" node "chassis324b" "pdu25" "34" node "chassis325a" "pdu25" "30" node "chassis325b" "pdu25" "27" node "chassis326a" "pdu25" "29" node "chassis326b" "pdu25" "26" node "chassis327a" "pdu25" "28" node "chassis327b" "pdu25" "25" node "chassis328a" "pdu25" "23" node "chassis328b" "pdu25" "20" node "chassis329a" "pdu25" "19" node "chassis329b" "pdu25" "16" node "chassis330a" "pdu25" "18" node "chassis330b" "pdu25" "15" node "chassis331a" "pdu25" "13" node "chassis331b" "pdu25" "10" node "chassis332a" "pdu25" "12" node "chassis332b" "pdu25" "9" node "chassis333a" "pdu25" "11" node "chassis333b" "pdu25" "8" node "chassis334a" "pdu25" "6" node "chassis334b" "pdu25" "3" node "chassis335a" "pdu25" "5" node "chassis335b" "pdu25" "2" node "chassis336a" "pdu25" "4" #sierra[1400,1402] node "chassis336b" "pdu25" "1" #sierra[1401,1403] # Rack 26 node "chassis337a" "pdu26" "48" #sierra[1404,1406] node "chassis337b" "pdu26" "45" #sierra[1405,1407] node "chassis338a" "pdu26" "47" node "chassis338b" "pdu26" "44" node "chassis339a" "pdu26" "43" node "chassis339b" "pdu26" "40" node "chassis340a" "pdu26" "41" node "chassis340b" "pdu26" "38" node "chassis341a" "pdu26" "39" node "chassis341b" "pdu26" "36" node "chassis342a" "pdu26" "37" node "chassis342b" "pdu26" "34" node "chassis343a" "pdu26" "30" node "chassis343b" "pdu26" "27" node "chassis344a" "pdu26" "29" node "chassis344b" "pdu26" "26" node "chassis345a" "pdu26" "28" node "chassis345b" "pdu26" "25" node "chassis346a" "pdu26" "23" node "chassis346b" "pdu26" "20" node "chassis347a" "pdu26" "19" node "chassis347b" "pdu26" "16" node "chassis348a" "pdu26" "18" node "chassis348b" "pdu26" "15" node "chassis349a" "pdu26" "13" node "chassis349b" "pdu26" "10" node "chassis350a" "pdu26" "12" node "chassis350b" "pdu26" "9" node "chassis351a" "pdu26" "11" node "chassis351b" "pdu26" "8" node "chassis352a" "pdu26" "6" node "chassis352b" "pdu26" "3" node "chassis353a" "pdu26" "5" node "chassis353b" "pdu26" "2" node "chassis354a" "pdu26" "4" #sierra[1472,1474] node "chassis354b" "pdu26" "1" #sierra[1473,1475] # Rack 27 node "chassis355a" "pdu27" "48" #sierra[1476,1478] node "chassis355b" "pdu27" "45" #sierra[1475,1477] node "chassis356a" "pdu27" "47" node "chassis356b" "pdu27" "44" node "chassis357a" "pdu27" "43" node "chassis357b" "pdu27" "40" node "chassis358a" "pdu27" "41" node "chassis358b" "pdu27" "38" node "chassis359a" "pdu27" "39" node "chassis359b" "pdu27" "36" node "chassis360a" "pdu27" "37" node "chassis360b" "pdu27" "34" node "chassis361a" "pdu27" "30" node "chassis361b" "pdu27" "27" node "chassis362a" "pdu27" "29" node "chassis362b" "pdu27" "26" node "chassis363a" "pdu27" "28" node "chassis363b" "pdu27" "25" node "chassis364a" "pdu27" "23" node "chassis364b" "pdu27" "20" node "chassis365a" "pdu27" "19" node "chassis365b" "pdu27" "16" node "chassis366a" "pdu27" "18" node "chassis366b" "pdu27" "15" node "chassis367a" "pdu27" "13" node "chassis367b" "pdu27" "10" node "chassis368a" "pdu27" "12" node "chassis368b" "pdu27" "9" node "chassis369a" "pdu27" "11" node "chassis369b" "pdu27" "8" node "chassis370a" "pdu27" "6" node "chassis370b" "pdu27" "3" node "chassis371a" "pdu27" "5" node "chassis371b" "pdu27" "2" node "chassis372a" "pdu27" "4" #sierra[1544,1546] node "chassis372b" "pdu27" "1" #sierra[1545,1547] # Rack 28 node "chassis373a" "pdu28" "48" #sierra[1548,1550] node "chassis373b" "pdu28" "45" #sierra[1549,1551] node "chassis374a" "pdu28" "47" node "chassis374b" "pdu28" "44" node "chassis375a" "pdu28" "43" node "chassis375b" "pdu28" "40" node "chassis376a" "pdu28" "41" node "chassis376b" "pdu28" "38" node "chassis377a" "pdu28" "39" node "chassis377b" "pdu28" "36" node "chassis378a" "pdu28" "37" node "chassis378b" "pdu28" "34" node "chassis379a" "pdu28" "30" node "chassis379b" "pdu28" "27" node "chassis380a" "pdu28" "29" node "chassis380b" "pdu28" "26" node "chassis381a" "pdu28" "28" node "chassis381b" "pdu28" "25" node "chassis382a" "pdu28" "23" node "chassis382b" "pdu28" "20" node "chassis383a" "pdu28" "19" node "chassis383b" "pdu28" "16" node "chassis384a" "pdu28" "18" node "chassis384b" "pdu28" "15" node "chassis385a" "pdu28" "13" node "chassis385b" "pdu28" "10" node "chassis386a" "pdu28" "12" node "chassis386b" "pdu28" "9" node "chassis387a" "pdu28" "11" node "chassis387b" "pdu28" "8" node "chassis388a" "pdu28" "6" node "chassis388b" "pdu28" "3" node "chassis389a" "pdu28" "5" node "chassis389b" "pdu28" "2" node "chassis390a" "pdu28" "4" #sierra[1616,1618] node "chassis390b" "pdu28" "1" #sierra[1617,1619] # Rack 29 LSM,RPS,GW nodes node "pdu-sierra1621a" "pdu29" "47" #sierra1621ps1 node "pdu-sierra1620" "pdu29" "46" #sierra1620 node "pdu-sierra1621b" "pdu29" "44" #sierra1621ps2 node "pdu-sierra1622" "pdu29" "43" #sierra1622 node "pdu-sierra1623" "pdu29" "42" #sierra1623 node "pdu-sierra1624" "pdu29" "41" #sierra1624 node "pdu-sierra1627a" "pdu29" "40" #sierra1627ps1 node "pdu-sierra1625" "pdu29" "39" #sierra1625 node "pdu-sierra1627b" "pdu29" "37" #sierra1627ps2 node "pdu-sierra1626" "pdu29" "36" #sierra1626 node "pdu-sierra1628" "pdu29" "34" #sierra1628 node "pdu-sierra1629" "pdu29" "32" #sierra1629 node "pdu-sierra1630" "pdu29" "31" #sierra1630 node "pdu-sierra1631" "pdu29" "29" #sierra1631 # Rack 29 Compute nodes node "chassis391a" "pdu29" "23" #sierra[1632,1634] node "chassis391b" "pdu29" "20" #sierra[1633,1635] node "chassis392a" "pdu29" "18" node "chassis392b" "pdu29" "15" node "chassis393a" "pdu29" "13" node "chassis393b" "pdu29" "10" node "chassis394a" "pdu29" "12" node "chassis394b" "pdu29" "9" node "chassis395a" "pdu29" "5" node "chassis395b" "pdu29" "2" node "chassis396a" "pdu29" "4" #sierra[1652,1654] node "chassis396b" "pdu29" "1" #sierra[1653,1655] # Rack 30 node "chassis397a" "pdu30" "48" #sierra[1656,1658] node "chassis397b" "pdu30" "45" #sierra[1657,1659] node "chassis398a" "pdu30" "47" node "chassis398b" "pdu30" "44" node "chassis399a" "pdu30" "43" node "chassis399b" "pdu30" "40" node "chassis400a" "pdu30" "41" node "chassis400b" "pdu30" "38" node "chassis401a" "pdu30" "39" node "chassis401b" "pdu30" "36" node "chassis402a" "pdu30" "37" node "chassis402b" "pdu30" "34" node "chassis403a" "pdu30" "30" node "chassis403b" "pdu30" "27" node "chassis404a" "pdu30" "29" node "chassis404b" "pdu30" "26" node "chassis405a" "pdu30" "28" node "chassis405b" "pdu30" "25" node "chassis406a" "pdu30" "23" node "chassis406b" "pdu30" "20" node "chassis407a" "pdu30" "19" node "chassis407b" "pdu30" "16" node "chassis408a" "pdu30" "18" node "chassis408b" "pdu30" "15" node "chassis409a" "pdu30" "13" node "chassis409b" "pdu30" "10" node "chassis410a" "pdu30" "12" node "chassis410b" "pdu30" "9" node "chassis411a" "pdu30" "11" node "chassis411b" "pdu30" "8" node "chassis412a" "pdu30" "6" node "chassis412b" "pdu30" "3" node "chassis413a" "pdu30" "5" node "chassis413b" "pdu30" "2" node "chassis414a" "pdu30" "4" #sierra[1724,1726] node "chassis414b" "pdu30" "1" #sierra[1725,1727] # Rack 31 node "chassis415a" "pdu31" "48" #sierra[1728,1730] node "chassis415b" "pdu31" "45" #sierra[1729,1731] node "chassis416a" "pdu31" "47" node "chassis416b" "pdu31" "44" node "chassis417a" "pdu31" "43" node "chassis417b" "pdu31" "40" node "chassis418a" "pdu31" "41" node "chassis418b" "pdu31" "38" node "chassis419a" "pdu31" "39" node "chassis419b" "pdu31" "36" node "chassis420a" "pdu31" "37" node "chassis420b" "pdu31" "34" node "chassis421a" "pdu31" "30" node "chassis421b" "pdu31" "27" node "chassis422a" "pdu31" "29" node "chassis422b" "pdu31" "26" node "chassis423a" "pdu31" "28" node "chassis423b" "pdu31" "25" node "chassis424a" "pdu31" "23" node "chassis424b" "pdu31" "20" node "chassis425a" "pdu31" "19" node "chassis425b" "pdu31" "16" node "chassis426a" "pdu31" "18" node "chassis426b" "pdu31" "15" node "chassis427a" "pdu31" "13" node "chassis427b" "pdu31" "10" node "chassis428a" "pdu31" "12" node "chassis428b" "pdu31" "9" node "chassis429a" "pdu31" "11" node "chassis429b" "pdu31" "8" node "chassis430a" "pdu31" "6" node "chassis430b" "pdu31" "3" node "chassis431a" "pdu31" "5" node "chassis431b" "pdu31" "2" node "chassis432a" "pdu31" "4" #sierra[1796,1798] node "chassis432b" "pdu31" "1" #sierra[1797,1799] # Rack 32 node "chassis433a" "pdu32" "48" #sierra[1800,1802] node "chassis433b" "pdu32" "45" #sierra[1801,1803] node "chassis434a" "pdu32" "47" node "chassis434b" "pdu32" "44" node "chassis435a" "pdu32" "43" node "chassis435b" "pdu32" "40" node "chassis436a" "pdu32" "41" node "chassis436b" "pdu32" "38" node "chassis437a" "pdu32" "39" node "chassis437b" "pdu32" "36" node "chassis438a" "pdu32" "37" node "chassis438b" "pdu32" "34" node "chassis439a" "pdu32" "30" node "chassis439b" "pdu32" "27" node "chassis440a" "pdu32" "29" node "chassis440b" "pdu32" "26" node "chassis441a" "pdu32" "28" node "chassis441b" "pdu32" "25" node "chassis442a" "pdu32" "23" node "chassis442b" "pdu32" "20" node "chassis443a" "pdu32" "19" node "chassis443b" "pdu32" "16" node "chassis444a" "pdu32" "18" node "chassis444b" "pdu32" "15" node "chassis445a" "pdu32" "13" node "chassis445b" "pdu32" "10" node "chassis446a" "pdu32" "12" node "chassis446b" "pdu32" "9" node "chassis447a" "pdu32" "11" node "chassis447b" "pdu32" "8" node "chassis448a" "pdu32" "6" node "chassis448b" "pdu32" "3" node "chassis449a" "pdu32" "5" node "chassis449b" "pdu32" "2" node "chassis450a" "pdu32" "4" #sierra[1868,1870] node "chassis450b" "pdu32" "1" #sierra[1869,1871] # Rack 33 node "chassis451a" "pdu33" "48" #sierra[1872,1874] node "chassis451b" "pdu33" "45" #sierra[1873,1875] node "chassis452a" "pdu33" "47" node "chassis452b" "pdu33" "44" node "chassis453a" "pdu33" "43" node "chassis453b" "pdu33" "40" node "chassis454a" "pdu33" "41" node "chassis454b" "pdu33" "38" node "chassis455a" "pdu33" "39" node "chassis455b" "pdu33" "36" node "chassis456a" "pdu33" "37" node "chassis456b" "pdu33" "34" node "chassis457a" "pdu33" "30" node "chassis457b" "pdu33" "27" node "chassis458a" "pdu33" "29" node "chassis458b" "pdu33" "26" node "chassis459a" "pdu33" "28" node "chassis459b" "pdu33" "25" node "chassis460a" "pdu33" "23" node "chassis460b" "pdu33" "20" node "chassis461a" "pdu33" "19" node "chassis461b" "pdu33" "16" node "chassis462a" "pdu33" "18" node "chassis462b" "pdu33" "15" node "chassis463a" "pdu33" "13" node "chassis463b" "pdu33" "10" node "chassis464a" "pdu33" "12" node "chassis464b" "pdu33" "9" node "chassis465a" "pdu33" "11" node "chassis465b" "pdu33" "8" node "chassis466a" "pdu33" "6" node "chassis466b" "pdu33" "3" node "chassis467a" "pdu33" "5" node "chassis467b" "pdu33" "2" node "chassis468a" "pdu33" "4" #sierra[1940,1942] node "chassis468b" "pdu33" "1" #sierra[1941,1943] # ALIAS section. # mgmt alias #alias "sierra1" "pdu-sierra1a pdu-sierra1b" #alias "sierra7" "pdu-sierra7a pdu-sierra7b" #alias "sierra325" "pdu-sierra325a pdu-sierra325b" #alias "sierra331" "pdu-sierra331a pdu-sierra331b" #alias "sierra649" "pdu-sierra649a pdu-sierra649b" #alias "sierra655" "pdu-sierra655a pdu-sierra655b" #alias "sierra973" "pdu-sierra973a pdu-sierra973b" #alias "sierra979" "pdu-sierra979a pdu-sierra979b" #alias "sierra1297" "pdu-sierra1297a pdu-sierra1297b" #alias "sierra1303" "pdu-sierra1303a pdu-sierra1303b" #alias "sierra1621" "pdu-sierra1621a pdu-sierra1621b" #alias "sierra1627" "pdu-sierra1627a pdu-sierra1627b" # more alias alias "chassis1" "chassis1a chassis1b" alias "chassis2" "chassis2a chassis2b" alias "chassis3" "chassis3a chassis3b" alias "chassis4" "chassis4a chassis4b" alias "chassis5" "chassis5a chassis5b" alias "chassis6" "chassis6a chassis6b" alias "chassis7" "chassis7a chassis7b" alias "chassis8" "chassis8a chassis8b" alias "chassis9" "chassis9a chassis9b" alias "chassis10" "chassis10a chassis10b" alias "chassis11" "chassis11a chassis11b" alias "chassis12" "chassis12a chassis12b" alias "chassis13" "chassis13a chassis13b" alias "chassis14" "chassis14a chassis14b" alias "chassis15" "chassis15a chassis15b" alias "chassis16" "chassis16a chassis16b" alias "chassis17" "chassis17a chassis17b" alias "chassis18" "chassis18a chassis18b" alias "chassis19" "chassis19a chassis19b" alias "chassis20" "chassis20a chassis20b" alias "chassis21" "chassis21a chassis21b" alias "chassis22" "chassis22a chassis22b" alias "chassis23" "chassis23a chassis23b" alias "chassis24" "chassis24a chassis24b" alias "chassis25" "chassis25a chassis25b" alias "chassis26" "chassis26a chassis26b" alias "chassis27" "chassis27a chassis27b" alias "chassis28" "chassis28a chassis28b" alias "chassis29" "chassis29a chassis29b" alias "chassis30" "chassis30a chassis30b" alias "chassis31" "chassis31a chassis31b" alias "chassis32" "chassis32a chassis32b" alias "chassis33" "chassis33a chassis33b" alias "chassis34" "chassis34a chassis34b" alias "chassis35" "chassis35a chassis35b" alias "chassis36" "chassis36a chassis36b" alias "chassis37" "chassis37a chassis37b" alias "chassis38" "chassis38a chassis38b" alias "chassis39" "chassis39a chassis39b" alias "chassis40" "chassis40a chassis40b" alias "chassis41" "chassis41a chassis41b" alias "chassis42" "chassis42a chassis42b" alias "chassis43" "chassis43a chassis43b" alias "chassis44" "chassis44a chassis44b" alias "chassis45" "chassis45a chassis45b" alias "chassis46" "chassis46a chassis46b" alias "chassis47" "chassis47a chassis47b" alias "chassis48" "chassis48a chassis48b" alias "chassis49" "chassis49a chassis49b" alias "chassis50" "chassis50a chassis50b" alias "chassis51" "chassis51a chassis51b" alias "chassis52" "chassis52a chassis52b" alias "chassis53" "chassis53a chassis53b" alias "chassis54" "chassis54a chassis54b" alias "chassis55" "chassis55a chassis55b" alias "chassis56" "chassis56a chassis56b" alias "chassis57" "chassis57a chassis57b" alias "chassis58" "chassis58a chassis58b" alias "chassis59" "chassis59a chassis59b" alias "chassis60" "chassis60a chassis60b" alias "chassis61" "chassis61a chassis61b" alias "chassis62" "chassis62a chassis62b" alias "chassis63" "chassis63a chassis63b" alias "chassis64" "chassis64a chassis64b" alias "chassis65" "chassis65a chassis65b" alias "chassis66" "chassis66a chassis66b" alias "chassis67" "chassis67a chassis67b" alias "chassis68" "chassis68a chassis68b" alias "chassis69" "chassis69a chassis69b" alias "chassis70" "chassis70a chassis70b" alias "chassis71" "chassis71a chassis71b" alias "chassis72" "chassis72a chassis72b" alias "chassis73" "chassis73a chassis73b" alias "chassis74" "chassis74a chassis74b" alias "chassis75" "chassis75a chassis75b" alias "chassis76" "chassis76a chassis76b" alias "chassis77" "chassis77a chassis77b" alias "chassis78" "chassis78a chassis78b" alias "chassis79" "chassis79a chassis79b" alias "chassis80" "chassis80a chassis80b" alias "chassis81" "chassis81a chassis81b" alias "chassis82" "chassis82a chassis82b" alias "chassis83" "chassis83a chassis83b" alias "chassis84" "chassis84a chassis84b" alias "chassis85" "chassis85a chassis85b" alias "chassis86" "chassis86a chassis86b" alias "chassis87" "chassis87a chassis87b" alias "chassis88" "chassis88a chassis88b" alias "chassis89" "chassis89a chassis89b" alias "chassis90" "chassis90a chassis90b" alias "chassis91" "chassis91a chassis91b" alias "chassis92" "chassis92a chassis92b" alias "chassis93" "chassis93a chassis93b" alias "chassis94" "chassis94a chassis94b" alias "chassis95" "chassis95a chassis95b" alias "chassis96" "chassis96a chassis96b" alias "chassis97" "chassis97a chassis97b" alias "chassis98" "chassis98a chassis98b" alias "chassis99" "chassis99a chassis99b" alias "chassis100" "chassis100a chassis100b" alias "chassis101" "chassis101a chassis101b" alias "chassis102" "chassis102a chassis102b" alias "chassis103" "chassis103a chassis103b" alias "chassis104" "chassis104a chassis104b" alias "chassis105" "chassis105a chassis105b" alias "chassis106" "chassis106a chassis106b" alias "chassis107" "chassis107a chassis107b" alias "chassis108" "chassis108a chassis108b" alias "chassis109" "chassis109a chassis109b" alias "chassis110" "chassis110a chassis110b" alias "chassis111" "chassis111a chassis111b" alias "chassis112" "chassis112a chassis112b" alias "chassis113" "chassis113a chassis113b" alias "chassis114" "chassis114a chassis114b" alias "chassis115" "chassis115a chassis115b" alias "chassis116" "chassis116a chassis116b" alias "chassis117" "chassis117a chassis117b" alias "chassis118" "chassis118a chassis118b" alias "chassis119" "chassis119a chassis119b" alias "chassis120" "chassis120a chassis120b" alias "chassis121" "chassis121a chassis121b" alias "chassis122" "chassis122a chassis122b" alias "chassis123" "chassis123a chassis123b" alias "chassis124" "chassis124a chassis124b" alias "chassis125" "chassis125a chassis125b" alias "chassis126" "chassis126a chassis126b" alias "chassis127" "chassis127a chassis127b" alias "chassis128" "chassis128a chassis128b" alias "chassis129" "chassis129a chassis129b" alias "chassis130" "chassis130a chassis130b" alias "chassis131" "chassis131a chassis131b" alias "chassis132" "chassis132a chassis132b" alias "chassis133" "chassis133a chassis133b" alias "chassis134" "chassis134a chassis134b" alias "chassis135" "chassis135a chassis135b" alias "chassis136" "chassis136a chassis136b" alias "chassis137" "chassis137a chassis137b" alias "chassis138" "chassis138a chassis138b" alias "chassis139" "chassis139a chassis139b" alias "chassis140" "chassis140a chassis140b" alias "chassis141" "chassis141a chassis141b" alias "chassis142" "chassis142a chassis142b" alias "chassis143" "chassis143a chassis143b" alias "chassis144" "chassis144a chassis144b" alias "chassis145" "chassis145a chassis145b" alias "chassis146" "chassis146a chassis146b" alias "chassis147" "chassis147a chassis147b" alias "chassis148" "chassis148a chassis148b" alias "chassis149" "chassis149a chassis149b" alias "chassis150" "chassis150a chassis150b" alias "chassis151" "chassis151a chassis151b" alias "chassis152" "chassis152a chassis152b" alias "chassis153" "chassis153a chassis153b" alias "chassis154" "chassis154a chassis154b" alias "chassis155" "chassis155a chassis155b" alias "chassis156" "chassis156a chassis156b" alias "chassis157" "chassis157a chassis157b" alias "chassis158" "chassis158a chassis158b" alias "chassis159" "chassis159a chassis159b" alias "chassis160" "chassis160a chassis160b" alias "chassis161" "chassis161a chassis161b" alias "chassis162" "chassis162a chassis162b" alias "chassis163" "chassis163a chassis163b" alias "chassis164" "chassis164a chassis164b" alias "chassis165" "chassis165a chassis165b" alias "chassis166" "chassis166a chassis166b" alias "chassis167" "chassis167a chassis167b" alias "chassis168" "chassis168a chassis168b" alias "chassis169" "chassis169a chassis169b" alias "chassis170" "chassis170a chassis170b" alias "chassis171" "chassis171a chassis171b" alias "chassis172" "chassis172a chassis172b" alias "chassis173" "chassis173a chassis173b" alias "chassis174" "chassis174a chassis174b" alias "chassis175" "chassis175a chassis175b" alias "chassis176" "chassis176a chassis176b" alias "chassis177" "chassis177a chassis177b" alias "chassis178" "chassis178a chassis178b" alias "chassis179" "chassis179a chassis179b" alias "chassis180" "chassis180a chassis180b" alias "chassis181" "chassis181a chassis181b" alias "chassis182" "chassis182a chassis182b" alias "chassis183" "chassis183a chassis183b" alias "chassis184" "chassis184a chassis184b" alias "chassis185" "chassis185a chassis185b" alias "chassis186" "chassis186a chassis186b" alias "chassis187" "chassis187a chassis187b" alias "chassis188" "chassis188a chassis188b" alias "chassis189" "chassis189a chassis189b" alias "chassis190" "chassis190a chassis190b" alias "chassis191" "chassis191a chassis191b" alias "chassis192" "chassis192a chassis192b" alias "chassis193" "chassis193a chassis193b" alias "chassis194" "chassis194a chassis194b" alias "chassis195" "chassis195a chassis195b" alias "chassis196" "chassis196a chassis196b" alias "chassis197" "chassis197a chassis197b" alias "chassis198" "chassis198a chassis198b" alias "chassis199" "chassis199a chassis199b" alias "chassis200" "chassis200a chassis200b" alias "chassis201" "chassis201a chassis201b" alias "chassis202" "chassis202a chassis202b" alias "chassis203" "chassis203a chassis203b" alias "chassis204" "chassis204a chassis204b" alias "chassis205" "chassis205a chassis205b" alias "chassis206" "chassis206a chassis206b" alias "chassis207" "chassis207a chassis207b" alias "chassis208" "chassis208a chassis208b" alias "chassis209" "chassis209a chassis209b" alias "chassis210" "chassis210a chassis210b" alias "chassis211" "chassis211a chassis211b" alias "chassis212" "chassis212a chassis212b" alias "chassis213" "chassis213a chassis213b" alias "chassis214" "chassis214a chassis214b" alias "chassis215" "chassis215a chassis215b" alias "chassis216" "chassis216a chassis216b" alias "chassis217" "chassis217a chassis217b" alias "chassis218" "chassis218a chassis218b" alias "chassis219" "chassis219a chassis219b" alias "chassis220" "chassis220a chassis220b" alias "chassis221" "chassis221a chassis221b" alias "chassis222" "chassis222a chassis222b" alias "chassis223" "chassis223a chassis223b" alias "chassis224" "chassis224a chassis224b" alias "chassis225" "chassis225a chassis225b" alias "chassis226" "chassis226a chassis226b" alias "chassis227" "chassis227a chassis227b" alias "chassis228" "chassis228a chassis228b" alias "chassis229" "chassis229a chassis229b" alias "chassis230" "chassis230a chassis230b" alias "chassis231" "chassis231a chassis231b" alias "chassis232" "chassis232a chassis232b" alias "chassis233" "chassis233a chassis233b" alias "chassis234" "chassis234a chassis234b" alias "chassis235" "chassis235a chassis235b" alias "chassis236" "chassis236a chassis236b" alias "chassis237" "chassis237a chassis237b" alias "chassis238" "chassis238a chassis238b" alias "chassis239" "chassis239a chassis239b" alias "chassis240" "chassis240a chassis240b" alias "chassis241" "chassis241a chassis241b" alias "chassis242" "chassis242a chassis242b" alias "chassis243" "chassis243a chassis243b" alias "chassis244" "chassis244a chassis244b" alias "chassis245" "chassis245a chassis245b" alias "chassis246" "chassis246a chassis246b" alias "chassis247" "chassis247a chassis247b" alias "chassis248" "chassis248a chassis248b" alias "chassis249" "chassis249a chassis249b" alias "chassis250" "chassis250a chassis250b" alias "chassis251" "chassis251a chassis251b" alias "chassis252" "chassis252a chassis252b" alias "chassis253" "chassis253a chassis253b" alias "chassis254" "chassis254a chassis254b" alias "chassis255" "chassis255a chassis255b" alias "chassis256" "chassis256a chassis256b" alias "chassis257" "chassis257a chassis257b" alias "chassis258" "chassis258a chassis258b" alias "chassis259" "chassis259a chassis259b" alias "chassis260" "chassis260a chassis260b" alias "chassis261" "chassis261a chassis261b" alias "chassis262" "chassis262a chassis262b" alias "chassis263" "chassis263a chassis263b" alias "chassis264" "chassis264a chassis264b" alias "chassis265" "chassis265a chassis265b" alias "chassis266" "chassis266a chassis266b" alias "chassis267" "chassis267a chassis267b" alias "chassis268" "chassis268a chassis268b" alias "chassis269" "chassis269a chassis269b" alias "chassis270" "chassis270a chassis270b" alias "chassis271" "chassis271a chassis271b" alias "chassis272" "chassis272a chassis272b" alias "chassis273" "chassis273a chassis273b" alias "chassis274" "chassis274a chassis274b" alias "chassis275" "chassis275a chassis275b" alias "chassis276" "chassis276a chassis276b" alias "chassis277" "chassis277a chassis277b" alias "chassis278" "chassis278a chassis278b" alias "chassis279" "chassis279a chassis279b" alias "chassis280" "chassis280a chassis280b" alias "chassis281" "chassis281a chassis281b" alias "chassis282" "chassis282a chassis282b" alias "chassis283" "chassis283a chassis283b" alias "chassis284" "chassis284a chassis284b" alias "chassis285" "chassis285a chassis285b" alias "chassis286" "chassis286a chassis286b" alias "chassis287" "chassis287a chassis287b" alias "chassis288" "chassis288a chassis288b" alias "chassis289" "chassis289a chassis289b" alias "chassis290" "chassis290a chassis290b" alias "chassis291" "chassis291a chassis291b" alias "chassis292" "chassis292a chassis292b" alias "chassis293" "chassis293a chassis293b" alias "chassis294" "chassis294a chassis294b" alias "chassis295" "chassis295a chassis295b" alias "chassis296" "chassis296a chassis296b" alias "chassis297" "chassis297a chassis297b" alias "chassis298" "chassis298a chassis298b" alias "chassis299" "chassis299a chassis299b" alias "chassis300" "chassis300a chassis300b" alias "chassis301" "chassis301a chassis301b" alias "chassis302" "chassis302a chassis302b" alias "chassis303" "chassis303a chassis303b" alias "chassis304" "chassis304a chassis304b" alias "chassis305" "chassis305a chassis305b" alias "chassis306" "chassis306a chassis306b" alias "chassis307" "chassis307a chassis307b" alias "chassis308" "chassis308a chassis308b" alias "chassis309" "chassis309a chassis309b" alias "chassis310" "chassis310a chassis310b" alias "chassis311" "chassis311a chassis311b" alias "chassis312" "chassis312a chassis312b" alias "chassis313" "chassis313a chassis313b" alias "chassis314" "chassis314a chassis314b" alias "chassis315" "chassis315a chassis315b" alias "chassis316" "chassis316a chassis316b" alias "chassis317" "chassis317a chassis317b" alias "chassis318" "chassis318a chassis318b" alias "chassis319" "chassis319a chassis319b" alias "chassis320" "chassis320a chassis320b" alias "chassis321" "chassis321a chassis321b" alias "chassis322" "chassis322a chassis322b" alias "chassis323" "chassis323a chassis323b" alias "chassis324" "chassis324a chassis324b" alias "chassis325" "chassis325a chassis325b" alias "chassis326" "chassis326a chassis326b" alias "chassis327" "chassis327a chassis327b" alias "chassis328" "chassis328a chassis328b" alias "chassis329" "chassis329a chassis329b" alias "chassis330" "chassis330a chassis330b" alias "chassis331" "chassis331a chassis331b" alias "chassis332" "chassis332a chassis332b" alias "chassis333" "chassis333a chassis333b" alias "chassis334" "chassis334a chassis334b" alias "chassis335" "chassis335a chassis335b" alias "chassis336" "chassis336a chassis336b" alias "chassis337" "chassis337a chassis337b" alias "chassis338" "chassis338a chassis338b" alias "chassis339" "chassis339a chassis339b" alias "chassis340" "chassis340a chassis340b" alias "chassis341" "chassis341a chassis341b" alias "chassis342" "chassis342a chassis342b" alias "chassis343" "chassis343a chassis343b" alias "chassis344" "chassis344a chassis344b" alias "chassis345" "chassis345a chassis345b" alias "chassis346" "chassis346a chassis346b" alias "chassis347" "chassis347a chassis347b" alias "chassis348" "chassis348a chassis348b" alias "chassis349" "chassis349a chassis349b" alias "chassis350" "chassis350a chassis350b" alias "chassis351" "chassis351a chassis351b" alias "chassis352" "chassis352a chassis352b" alias "chassis353" "chassis353a chassis353b" alias "chassis354" "chassis354a chassis354b" alias "chassis355" "chassis355a chassis355b" alias "chassis356" "chassis356a chassis356b" alias "chassis357" "chassis357a chassis357b" alias "chassis358" "chassis358a chassis358b" alias "chassis359" "chassis359a chassis359b" alias "chassis360" "chassis360a chassis360b" alias "chassis361" "chassis361a chassis361b" alias "chassis362" "chassis362a chassis362b" alias "chassis363" "chassis363a chassis363b" alias "chassis364" "chassis364a chassis364b" alias "chassis365" "chassis365a chassis365b" alias "chassis366" "chassis366a chassis366b" alias "chassis367" "chassis367a chassis367b" alias "chassis368" "chassis368a chassis368b" alias "chassis369" "chassis369a chassis369b" alias "chassis370" "chassis370a chassis370b" alias "chassis371" "chassis371a chassis371b" alias "chassis372" "chassis372a chassis372b" alias "chassis373" "chassis373a chassis373b" alias "chassis374" "chassis374a chassis374b" alias "chassis375" "chassis375a chassis375b" alias "chassis376" "chassis376a chassis376b" alias "chassis377" "chassis377a chassis377b" alias "chassis378" "chassis378a chassis378b" alias "chassis379" "chassis379a chassis379b" alias "chassis380" "chassis380a chassis380b" alias "chassis381" "chassis381a chassis381b" alias "chassis382" "chassis382a chassis382b" alias "chassis383" "chassis383a chassis383b" alias "chassis384" "chassis384a chassis384b" alias "chassis385" "chassis385a chassis385b" alias "chassis386" "chassis386a chassis386b" alias "chassis387" "chassis387a chassis387b" alias "chassis388" "chassis388a chassis388b" alias "chassis389" "chassis389a chassis389b" alias "chassis390" "chassis390a chassis390b" alias "chassis391" "chassis391a chassis391b" alias "chassis392" "chassis392a chassis392b" alias "chassis393" "chassis393a chassis393b" alias "chassis394" "chassis394a chassis394b" alias "chassis395" "chassis395a chassis395b" alias "chassis396" "chassis396a chassis396b" alias "chassis397" "chassis397a chassis397b" alias "chassis398" "chassis398a chassis398b" alias "chassis399" "chassis399a chassis399b" alias "chassis400" "chassis400a chassis400b" alias "chassis401" "chassis401a chassis401b" alias "chassis402" "chassis402a chassis402b" alias "chassis403" "chassis403a chassis403b" alias "chassis404" "chassis404a chassis404b" alias "chassis405" "chassis405a chassis405b" alias "chassis406" "chassis406a chassis406b" alias "chassis407" "chassis407a chassis407b" alias "chassis408" "chassis408a chassis408b" alias "chassis409" "chassis409a chassis409b" alias "chassis410" "chassis410a chassis410b" alias "chassis411" "chassis411a chassis411b" alias "chassis412" "chassis412a chassis412b" alias "chassis413" "chassis413a chassis413b" alias "chassis414" "chassis414a chassis414b" alias "chassis415" "chassis415a chassis415b" alias "chassis416" "chassis416a chassis416b" alias "chassis417" "chassis417a chassis417b" alias "chassis418" "chassis418a chassis418b" alias "chassis419" "chassis419a chassis419b" alias "chassis420" "chassis420a chassis420b" alias "chassis421" "chassis421a chassis421b" alias "chassis422" "chassis422a chassis422b" alias "chassis423" "chassis423a chassis423b" alias "chassis424" "chassis424a chassis424b" alias "chassis425" "chassis425a chassis425b" alias "chassis426" "chassis426a chassis426b" alias "chassis427" "chassis427a chassis427b" alias "chassis428" "chassis428a chassis428b" alias "chassis429" "chassis429a chassis429b" alias "chassis430" "chassis430a chassis430b" alias "chassis431" "chassis431a chassis431b" alias "chassis432" "chassis432a chassis432b" alias "chassis433" "chassis433a chassis433b" alias "chassis434" "chassis434a chassis434b" alias "chassis435" "chassis435a chassis435b" alias "chassis436" "chassis436a chassis436b" alias "chassis437" "chassis437a chassis437b" alias "chassis438" "chassis438a chassis438b" alias "chassis439" "chassis439a chassis439b" alias "chassis440" "chassis440a chassis440b" alias "chassis441" "chassis441a chassis441b" alias "chassis442" "chassis442a chassis442b" alias "chassis443" "chassis443a chassis443b" alias "chassis444" "chassis444a chassis444b" alias "chassis445" "chassis445a chassis445b" alias "chassis446" "chassis446a chassis446b" alias "chassis447" "chassis447a chassis447b" alias "chassis448" "chassis448a chassis448b" alias "chassis449" "chassis449a chassis449b" alias "chassis450" "chassis450a chassis450b" alias "chassis451" "chassis451a chassis451b" alias "chassis452" "chassis452a chassis452b" alias "chassis453" "chassis453a chassis453b" alias "chassis454" "chassis454a chassis454b" alias "chassis455" "chassis455a chassis455b" alias "chassis456" "chassis456a chassis456b" alias "chassis457" "chassis457a chassis457b" alias "chassis458" "chassis458a chassis458b" alias "chassis459" "chassis459a chassis459b" alias "chassis460" "chassis460a chassis460b" alias "chassis461" "chassis461a chassis461b" alias "chassis462" "chassis462a chassis462b" alias "chassis463" "chassis463a chassis463b" alias "chassis464" "chassis464a chassis464b" alias "chassis465" "chassis465a chassis465b" alias "chassis466" "chassis466a chassis466b" alias "chassis467" "chassis467a chassis467b" alias "chassis468" "chassis468a chassis468b" powerman-2.4.4/t/etc/valgrind.supp000066400000000000000000000001641467035776500171330ustar00rootroot00000000000000{ Memcheck:Leak match-leak-kinds: possible fun:malloc fun:list_alloc_aux ... } powerman-2.4.4/t/etc/vpc.dev000066400000000000000000000062671467035776500157160ustar00rootroot00000000000000# # $Id$ # specification "vpc" { timeout 5.0 plug name { "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" } script login { send "login\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script logout { send "logoff\n" expect "[0-9]* OK\n" } script status_all { send "stat *\n" foreachplug { expect "plug ([0-9]+): (ON|OFF|ERROR)\n" setplugstate $1 $2 on="ON" off="OFF" } expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script on { send "on %s\n" expect "([0-9]+): (OK|ERROR)\n" setresult $1 $2 success="OK" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script on_ranged { send "on %s\n" foreachplug { expect "([0-9]+): (OK|ERROR)\n" setresult $1 $2 success="OK" } expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script on_all { send "on *\n" foreachplug { expect "([0-9]+): (OK|ERROR)\n" setresult $1 $2 success="OK" } expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script off { send "off %s\n" expect "([0-9]+): (OK|ERROR)\n" setresult $1 $2 success="OK" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script off_ranged { send "off %s\n" foreachplug { expect "([0-9]+): (OK|ERROR)\n" setresult $1 $2 success="OK" } expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script off_all { send "off *\n" foreachplug { expect "([0-9]+): (OK|ERROR)\n" setresult $1 $2 success="OK" } expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script cycle { send "off %s\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " delay 1.0 send "on %s\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script cycle_ranged { send "off %s\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " delay 1.0 send "on %s\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script cycle_all { send "off *\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " delay 1.0 send "on *\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script beacon_on { send "flash %s\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script beacon_off { send "unflash %s\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script status_beacon_all { send "beacon *\n" foreachplug { expect "plug ([0-9]+): (ON|OFF|ERROR)\n" setplugstate $1 $2 on="ON" off="OFF" } expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script status_temp_all { send "temp *\n" foreachplug { expect "plug ([0-9]+): ([0-9]+)\n" setplugstate $1 $2 } expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script reset_all { send "reset *\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script reset_ranged { send "reset %s\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script reset { send "reset %s\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } } powerman-2.4.4/t/scripts/000077500000000000000000000000001467035776500153275ustar00rootroot00000000000000powerman-2.4.4/t/scripts/pm-sim.sh000077500000000000000000000042021467035776500170660ustar00rootroot00000000000000#!/bin/bash # # pm-sim - simulate just enough powerman to test powerman-stonith script # declare -r prog=pm-sim aopt=0 Aopt=0 onopt=0 offopt=0 queryopt=0 targ="" t1=off t2=off t3=off t=off ropt=0 sopt=0 topt=0 simstate=$prog.data [ -r $simstate ] && source $simstate PATH=/usr/bin:/bin:$PATH die() { echo "${prog}: $1" >&2 exit 1 } usage() { echo "Usage: ${prog} OPTIONS [-x] [-q|-0|-1] target" 2>&1 echo "where OPTIONS are:" 2>&1 echo " -a alias t t[1-2]" 2>&1 echo " -A alias t t[1-3]" 2>&1 echo " -m off|on set t1 initial state" 2>&1 echo " -n off|on set t2 initial state" 2>&1 echo " -o off|on set t3 initial state" 2>&1 echo " -r make t1 stuck" 2>&1 echo " -s make t2 stuck" 2>&1 echo " -t make t3 stuck" 2>&1 exit 1 } [ $# == 0 ] && usage while getopts "1:0:q:aAxm:n:o:rst" opt; do case ${opt} in 1) onopt=1; targ=${OPTARG} ;; 0) offopt=1; targ=${OPTARG} ;; q) queryopt=1; targ=${OPTARG} ;; x) ;; a) aopt=1 ;; A) Aopt=1 ;; m) t1=${OPTARG} ;; n) t2=${OPTARG} ;; o) t3=${OPTARG} ;; r) ropt=1 ;; s) sopt=1 ;; t) topt=1 ;; *) usage ;; esac done shift $((${OPTIND} - 1)) if [ "$onopt" == 1 ]; then [ $ropt == 1 ] || t1=on [ $sopt == 1 ] || t2=on [ $topt == 1 ] || t3=on echo Command completed successfully elif [ "$offopt" == 1 ]; then [ $ropt == 1 ] || t1=off [ $sopt == 1 ] || t2=off [ $topt == 1 ] || t3=off echo Command completed successfully elif [ "$queryopt" == 1 ]; then if [ "$aopt" == 1 ]; then echo "t1: $t1" echo "t2: $t2" elif [ "$Aopt" == 1 ]; then echo "t1: $t1" echo "t2: $t2" echo "t3: $t3" else if [ $t1 == on ] && [ $t2 == on ] && [ $t3 == on ]; then echo "t: on" elif [ $t1 == off ] && [ $t2 == off ] && [ $t3 == off ]; then echo "t: off" else echo "t: unknown" fi fi fi (echo t1=$t1; echo t2=$t2; echo t3=$t3) >$simstate exit 0 powerman-2.4.4/t/sharness.sh000077500000000000000000000560321467035776500160330ustar00rootroot00000000000000#!/bin/sh # # Copyright (c) 2011-2012 Mathias Lafeldt # Copyright (c) 2005-2012 Git project # Copyright (c) 2005-2012 Junio C Hamano # # 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 http://www.gnu.org/licenses/ . # Public: Current version of Sharness. SHARNESS_VERSION="1.0.0" export SHARNESS_VERSION # Public: The file extension for tests. By default, it is set to "t". : ${SHARNESS_TEST_EXTENSION:=t} export SHARNESS_TEST_EXTENSION # Reset TERM to original terminal if found, otherwise save orignal TERM [ "x" = "x$SHARNESS_ORIG_TERM" ] && SHARNESS_ORIG_TERM="$TERM" || TERM="$SHARNESS_ORIG_TERM" # Public: The unsanitized TERM under which sharness is originally run export SHARNESS_ORIG_TERM # Export SHELL_PATH : ${SHELL_PATH:=$SHELL} export SHELL_PATH # For repeatability, reset the environment to a known state. # TERM is sanitized below, after saving color control sequences. LANG=C LC_ALL=C PAGER=cat TZ=UTC EDITOR=: export LANG LC_ALL PAGER TZ EDITOR unset VISUAL CDPATH GREP_OPTIONS # Line feed LF=' ' [ "x$TERM" != "xdumb" ] && ( [ -t 1 ] && tput bold >/dev/null 2>&1 && tput setaf 1 >/dev/null 2>&1 && tput sgr0 >/dev/null 2>&1 ) && color=t while test "$#" -ne 0; do case "$1" in --logfile) logfile=t; shift;; -d|--d|--de|--deb|--debu|--debug) debug=t; shift ;; -i|--i|--im|--imm|--imme|--immed|--immedi|--immedia|--immediat|--immediate) immediate=t; shift ;; -l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests) TEST_LONG=t; export TEST_LONG; shift ;; --in|--int|--inte|--inter|--intera|--interac|--interact|--interacti|--interactiv|--interactive|--interactive-|--interactive-t|--interactive-te|--interactive-tes|--interactive-test|--interactive-tests): TEST_INTERACTIVE=t; export TEST_INTERACTIVE; verbose=t; shift ;; -h|--h|--he|--hel|--help) help=t; shift ;; -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose) verbose=t; shift ;; -q|--q|--qu|--qui|--quie|--quiet) # Ignore --quiet under a TAP::Harness. Saying how many tests # passed without the ok/not ok details is always an error. test -z "$HARNESS_ACTIVE" && quiet=t; shift ;; --chain-lint) chain_lint=t; shift ;; --no-chain-lint) chain_lint=; shift ;; --no-color) color=; shift ;; --root=*) root=$(expr "z$1" : 'z[^=]*=\(.*\)') shift ;; *) echo "error: unknown test option '$1'" >&2; exit 1 ;; esac done if test -n "$color"; then # Save the color control sequences now rather than run tput # each time say_color() is called. This is done for two # reasons: # * TERM will be changed to dumb # * HOME will be changed to a temporary directory and tput # might need to read ~/.terminfo from the original HOME # directory to get the control sequences # Note: This approach assumes the control sequences don't end # in a newline for any terminal of interest (command # substitutions strip trailing newlines). Given that most # (all?) terminals in common use are related to ECMA-48, this # shouldn't be a problem. say_color_error=$(tput bold; tput setaf 1) # bold red say_color_skip=$(tput setaf 4) # blue say_color_warn=$(tput setaf 3) # brown/yellow say_color_pass=$(tput setaf 2) # green say_color_info=$(tput setaf 6) # cyan say_color_reset=$(tput sgr0) say_color_="" # no formatting for normal text say_color() { test -z "$1" && test -n "$quiet" && return eval "say_color_color=\$say_color_$1" shift printf "%s\\n" "$say_color_color$*$say_color_reset" } else say_color() { test -z "$1" && test -n "$quiet" && return shift printf "%s\n" "$*" } fi TERM=dumb export TERM error() { say_color error "error: $*" EXIT_OK=t exit 1 } say() { say_color info "$*" } test -n "$test_description" || error "Test script did not set test_description." if test "$help" = "t"; then echo "$test_description" exit 0 fi exec 5>&1 exec 6<&0 if test "$verbose" = "t"; then exec 4>&2 3>&1 elif test "$logfile" = "t"; then logfile=$(basename $0 .t).output exec 4>${logfile} 3>&4 else exec 4>/dev/null 3>/dev/null fi test_failure=0 test_count=0 test_fixed=0 test_broken=0 test_success=0 die() { code=$? if test -n "$EXIT_OK"; then exit $code else echo >&5 "FATAL: Unexpected exit with code $code" exit 1 fi } EXIT_OK= trap 'die' EXIT # Public: Define that a test prerequisite is available. # # The prerequisite can later be checked explicitly using test_have_prereq or # implicitly by specifying the prerequisite name in calls to test_expect_success # or test_expect_failure. # # $1 - Name of prerequiste (a simple word, in all capital letters by convention) # # Examples # # # Set PYTHON prerequisite if interpreter is available. # command -v python >/dev/null && test_set_prereq PYTHON # # # Set prerequisite depending on some variable. # test -z "$NO_GETTEXT" && test_set_prereq GETTEXT # # Returns nothing. test_set_prereq() { satisfied_prereq="$satisfied_prereq$1 " } satisfied_prereq=" " # Public: Check if one or more test prerequisites are defined. # # The prerequisites must have previously been set with test_set_prereq. # The most common use of this is to skip all the tests if some essential # prerequisite is missing. # # $1 - Comma-separated list of test prerequisites. # # Examples # # # Skip all remaining tests if prerequisite is not set. # if ! test_have_prereq PERL; then # skip_all='skipping perl interface tests, perl not available' # test_done # fi # # Returns 0 if all prerequisites are defined or 1 otherwise. test_have_prereq() { # prerequisites can be concatenated with ',' save_IFS=$IFS IFS=, set -- $* IFS=$save_IFS total_prereq=0 ok_prereq=0 missing_prereq= for prerequisite; do case "$prerequisite" in !*) negative_prereq=t prerequisite=${prerequisite#!} ;; *) negative_prereq= esac total_prereq=$(($total_prereq + 1)) case "$satisfied_prereq" in *" $prerequisite "*) satisfied_this_prereq=t ;; *) satisfied_this_prereq= esac case "$satisfied_this_prereq,$negative_prereq" in t,|,t) ok_prereq=$(($ok_prereq + 1)) ;; *) # Keep a list of missing prerequisites; restore # the negative marker if necessary. prerequisite=${negative_prereq:+!}$prerequisite if test -z "$missing_prereq"; then missing_prereq=$prerequisite else missing_prereq="$prerequisite,$missing_prereq" fi esac done test $total_prereq = $ok_prereq } # You are not expected to call test_ok_ and test_failure_ directly, use # the text_expect_* functions instead. test_ok_() { test_success=$(($test_success + 1)) say_color "pass" "ok $test_count - $@" test -n "$logfile" && say >&3 "ok $test_count - $@" test -n "$logfile" && printf "%s\n" "$*" >&3 } test_failure_() { test_failure=$(($test_failure + 1)) say_color error "not ok $test_count - $1" test -n "$logfile" && say >&3 "not ok $test_count - $1" shift echo "$@" | sed -e 's/^/# /' test "$immediate" = "" || { EXIT_OK=t; exit 1; } } test_known_broken_ok_() { test_fixed=$(($test_fixed + 1)) say_color error "ok $test_count - $@ # TODO known breakage vanished" test -n "$logfile" && say >&3 "ok $test_count - $@ # TODO known breakage vanished" } test_known_broken_failure_() { test_broken=$(($test_broken + 1)) say_color warn "not ok $test_count - $@ # TODO known breakage" test -n "$logfile" && say >&3 "not ok $test_count - $@ # TODO known breakage" } # Public: Execute commands in debug mode. # # Takes a single argument and evaluates it only when the test script is started # with --debug. This is primarily meant for use during the development of test # scripts. # # $1 - Commands to be executed. # # Examples # # test_debug "cat some_log_file" # # Returns the exit code of the last command executed in debug mode or 0 # otherwise. test_debug() { test "$debug" = "" || eval "$1" } # Public: Stop execution and start a shell. # # This is useful for debugging tests and only makes sense together with "-v". # Be sure to remove all invocations of this command before submitting. test_pause() { if test "$verbose" = t; then "$SHELL_PATH" <&6 >&3 2>&4 else error >&5 "test_pause requires --verbose" fi } test_eval_() { # This is a separate function because some tests use # "return" to end a test_expect_success block early. case ",$test_prereq," in *,INTERACTIVE,*) eval "$*" ;; *) eval &3 2>&4 "$*" ;; esac } test_run_() { test_cleanup=: expecting_failure=$2 test_eval_ "$1" eval_ret=$? if test "$chain_lint" = "t"; then test_eval_ "(exit 117) && $1" if test "$?" != 117; then error "bug in the test script: broken &&-chain: $1" fi fi if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure"; then test_eval_ "$test_cleanup" fi if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then echo "" fi return "$eval_ret" } test_skip_() { test_count=$(($test_count + 1)) to_skip= for skp in $SKIP_TESTS; do case $this_test.$test_count in $skp) to_skip=t break esac done if test -z "$to_skip" && test -n "$test_prereq" && ! test_have_prereq "$test_prereq"; then to_skip=t fi case "$to_skip" in t) of_prereq= if test "$missing_prereq" != "$test_prereq"; then of_prereq=" of $test_prereq" fi say_color skip >&3 "skipping test: $@" say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})" : true ;; *) false ;; esac } # Public: Run test commands and expect them to succeed. # # When the test passed, an "ok" message is printed and the number of successful # tests is incremented. When it failed, a "not ok" message is printed and the # number of failed tests is incremented. # # With --immediate, exit test immediately upon the first failed test. # # Usually takes two arguments: # $1 - Test description # $2 - Commands to be executed. # # With three arguments, the first will be taken to be a prerequisite: # $1 - Comma-separated list of test prerequisites. The test will be skipped if # not all of the given prerequisites are set. To negate a prerequisite, # put a "!" in front of it. # $2 - Test description # $3 - Commands to be executed. # # Examples # # test_expect_success \ # 'git-write-tree should be able to write an empty tree.' \ # 'tree=$(git-write-tree)' # # # Test depending on one prerequisite. # test_expect_success TTY 'git --paginate rev-list uses a pager' \ # ' ... ' # # # Multiple prerequisites are separated by a comma. # test_expect_success PERL,PYTHON 'yo dawg' \ # ' test $(perl -E 'print eval "1 +" . qx[python -c "print 2"]') == "4" ' # # Returns nothing. test_expect_success() { test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test_expect_success" export test_prereq if ! test_skip_ "$@"; then say >&3 "expecting success: $2" if test_run_ "$2"; then test_ok_ "$1" else test_failure_ "$@" fi fi echo >&3 "" } # Public: Run test commands and expect them to fail. Used to demonstrate a known # breakage. # # This is NOT the opposite of test_expect_success, but rather used to mark a # test that demonstrates a known breakage. # # When the test passed, an "ok" message is printed and the number of fixed tests # is incremented. When it failed, a "not ok" message is printed and the number # of tests still broken is incremented. # # Failures from these tests won't cause --immediate to stop. # # Usually takes two arguments: # $1 - Test description # $2 - Commands to be executed. # # With three arguments, the first will be taken to be a prerequisite: # $1 - Comma-separated list of test prerequisites. The test will be skipped if # not all of the given prerequisites are set. To negate a prerequisite, # put a "!" in front of it. # $2 - Test description # $3 - Commands to be executed. # # Returns nothing. test_expect_failure() { test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test_expect_failure" export test_prereq if ! test_skip_ "$@"; then say >&3 "checking known breakage: $2" if test_run_ "$2" expecting_failure; then test_known_broken_ok_ "$1" else test_known_broken_failure_ "$1" fi fi echo >&3 "" } # Public: Run command and ensure that it fails in a controlled way. # # Use it instead of "! ". For example, when dies due to a # segfault, test_must_fail diagnoses it as an error, while "! " would # mistakenly be treated as just another expected failure. # # This is one of the prefix functions to be used inside test_expect_success or # test_expect_failure. # # $1.. - Command to be executed. # # Examples # # test_expect_success 'complain and die' ' # do something && # do something else && # test_must_fail git checkout ../outerspace # ' # # Returns 1 if the command succeeded (exit code 0). # Returns 1 if the command died by signal (exit codes 130-192) # Returns 1 if the command could not be found (exit code 127). # Returns 0 otherwise. test_must_fail() { "$@" exit_code=$? if test $exit_code = 0; then echo >&2 "test_must_fail: command succeeded: $*" return 1 elif test $exit_code -gt 129 -a $exit_code -le 192; then echo >&2 "test_must_fail: died by signal: $*" return 1 elif test $exit_code = 127; then echo >&2 "test_must_fail: command not found: $*" return 1 fi return 0 } # Public: Run command and ensure that it succeeds or fails in a controlled way. # # Similar to test_must_fail, but tolerates success too. Use it instead of # " || :" to catch failures caused by a segfault, for instance. # # This is one of the prefix functions to be used inside test_expect_success or # test_expect_failure. # # $1.. - Command to be executed. # # Examples # # test_expect_success 'some command works without configuration' ' # test_might_fail git config --unset all.configuration && # do something # ' # # Returns 1 if the command died by signal (exit codes 130-192) # Returns 1 if the command could not be found (exit code 127). # Returns 0 otherwise. test_might_fail() { "$@" exit_code=$? if test $exit_code -gt 129 -a $exit_code -le 192; then echo >&2 "test_might_fail: died by signal: $*" return 1 elif test $exit_code = 127; then echo >&2 "test_might_fail: command not found: $*" return 1 fi return 0 } # Public: Run command and ensure it exits with a given exit code. # # This is one of the prefix functions to be used inside test_expect_success or # test_expect_failure. # # $1 - Expected exit code. # $2.. - Command to be executed. # # Examples # # test_expect_success 'Merge with d/f conflicts' ' # test_expect_code 1 git merge "merge msg" B master # ' # # Returns 0 if the expected exit code is returned or 1 otherwise. test_expect_code() { want_code=$1 shift "$@" exit_code=$? if test $exit_code = $want_code; then return 0 fi echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*" return 1 } # Public: Compare two files to see if expected output matches actual output. # # The TEST_CMP variable defines the command used for the comparision; it # defaults to "diff -u". Only when the test script was started with --verbose, # will the command's output, the diff, be printed to the standard output. # # This is one of the prefix functions to be used inside test_expect_success or # test_expect_failure. # # $1 - Path to file with expected output. # $2 - Path to file with actual output. # # Examples # # test_expect_success 'foo works' ' # echo expected >expected && # foo >actual && # test_cmp expected actual # ' # # Returns the exit code of the command set by TEST_CMP. test_cmp() { ${TEST_CMP:-diff -u} "$@" } # Public: portably print a sequence of numbers. # # seq is not in POSIX and GNU seq might not be available everywhere, # so it is nice to have a seq implementation, even a very simple one. # # $1 - Starting number. # $2 - Ending number. # # Examples # # test_expect_success 'foo works 10 times' ' # for i in $(test_seq 1 10) # do # foo || return # done # ' # # Returns 0 if all the specified numbers can be displayed. test_seq() { i="$1" j="$2" while test "$i" -le "$j" do echo "$i" || return i=$(expr "$i" + 1) done } # Public: Check if the file expected to be empty is indeed empty, and barfs # otherwise. # # $1 - File to check for emptyness. # # Returns 0 if file is empty, 1 otherwise. test_must_be_empty() { if test -s "$1" then echo "'$1' is not empty, it contains:" cat "$1" return 1 fi } # Public: Schedule cleanup commands to be run unconditionally at the end of a # test. # # If some cleanup command fails, the test will not pass. With --immediate, no # cleanup is done to help diagnose what went wrong. # # This is one of the prefix functions to be used inside test_expect_success or # test_expect_failure. # # $1.. - Commands to prepend to the list of cleanup commands. # # Examples # # test_expect_success 'test core.capslock' ' # git config core.capslock true && # test_when_finished "git config --unset core.capslock" && # do_something # ' # # Returns the exit code of the last cleanup command executed. test_when_finished() { test_cleanup="{ $* } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup" } # Public: Schedule cleanup commands to be run unconditionally when all tests # have run. # # This can be used to clean up things like test databases. It is not needed to # clean up temporary files, as test_done already does that. # # Examples: # # cleanup mysql -e "DROP DATABASE mytest" # # Returns the exit code of the last cleanup command executed. final_cleanup= cleanup() { final_cleanup="{ $* } && (exit \"\$eval_ret\"); eval_ret=\$?; $final_cleanup" } # Public: Summarize test results and exit with an appropriate error code. # # Must be called at the end of each test script. # # Can also be used to stop tests early and skip all remaining tests. For this, # set skip_all to a string explaining why the tests were skipped before calling # test_done. # # Examples # # # Each test script must call test_done at the end. # test_done # # # Skip all remaining tests if prerequisite is not set. # if ! test_have_prereq PERL; then # skip_all='skipping perl interface tests, perl not available' # test_done # fi # # Returns 0 if all tests passed or 1 if there was a failure. test_done() { EXIT_OK=t if test -z "$HARNESS_ACTIVE"; then test_results_dir="$SHARNESS_TEST_DIRECTORY/test-results" mkdir -p "$test_results_dir" test_results_path="$test_results_dir/${SHARNESS_TEST_NAME}.$$.counts" cat >>"$test_results_path" <<-EOF total $test_count success $test_success fixed $test_fixed broken $test_broken failed $test_failure EOF fi if test "$test_fixed" != 0; then say_color error "# $test_fixed known breakage(s) vanished; please update test(s)" test -n "$logfile" && say >&3 "# $test_fixed known breakage(s) vanished" fi if test "$test_broken" != 0; then say_color warn "# still have $test_broken known breakage(s)" test -n "$logfile" && say >&3 "# still have $test_broken known breakage(s)" fi if test "$test_broken" != 0 || test "$test_fixed" != 0; then test_remaining=$(( $test_count - $test_broken - $test_fixed )) msg="remaining $test_remaining test(s)" else test_remaining=$test_count msg="$test_count test(s)" fi case "$test_failure" in 0) # Maybe print SKIP message if test -n "$skip_all" && test $test_count -gt 0; then error "Can't use skip_all after running some tests" fi [ -z "$skip_all" ] || skip_all=" # SKIP $skip_all" if test $test_remaining -gt 0; then say_color pass "# passed all $msg" test -n "$logfile" && say >&3 "# passed all $msg" fi say "1..$test_count$skip_all" test -n "$logfile" && say >&3 "1..$test_count$skip_all" test_eval_ "$final_cleanup" test -d "$remove_trash" && cd "$(dirname "$remove_trash")" && rm -rf "$(basename "$remove_trash")" test -n "$logfile" && test -f "$logfile" && rm -f "${logfile}" exit 0 ;; *) say_color error "# failed $test_failure among $msg" say "1..$test_count" if test -n "$logfile"; then say >&3 "# failed $test_failure among $msg" say >&3 "1..$test_count" fi exit 1 ;; esac } # Public: Root directory containing tests. Tests can override this variable, # e.g. for testing Sharness itself. : ${SHARNESS_TEST_DIRECTORY:=$(pwd)} export SHARNESS_TEST_DIRECTORY # Public: Source directory of test code and sharness library. # This directory may be different from the directory in which tests are # being run. : ${SHARNESS_TEST_SRCDIR:=$(cd $(dirname $0) && pwd)} export SHARNESS_TEST_SRCDIR # Public: Build directory that will be added to PATH. By default, it is set to # the parent directory of SHARNESS_TEST_DIRECTORY. : ${SHARNESS_BUILD_DIRECTORY:="$SHARNESS_TEST_DIRECTORY/.."} PATH="$SHARNESS_BUILD_DIRECTORY:$PATH" export PATH SHARNESS_BUILD_DIRECTORY # Public: Path to test script currently executed. SHARNESS_TEST_FILE="$0" export SHARNESS_TEST_FILE SHARNESS_TEST_NAME=${SHARNESS_TEST_FILE##*/} SHARNESS_TEST_NAME=${SHARNESS_TEST_NAME%.${SHARNESS_TEST_EXTENSION}} # Prepare test area. SHARNESS_TRASH_DIRECTORY="trash-directory.$SHARNESS_TEST_NAME" test -n "$root" && SHARNESS_TRASH_DIRECTORY="$root/$SHARNESS_TRASH_DIRECTORY" case "$SHARNESS_TRASH_DIRECTORY" in /*) ;; # absolute path is good *) SHARNESS_TRASH_DIRECTORY="$SHARNESS_TEST_DIRECTORY/$SHARNESS_TRASH_DIRECTORY" ;; esac test "$debug" = "t" || remove_trash="$SHARNESS_TRASH_DIRECTORY" rm -rf "$SHARNESS_TRASH_DIRECTORY" || { EXIT_OK=t echo >&5 "FATAL: Cannot prepare test area" exit 1 } # # Load any extensions in $srcdir/sharness.d/*.sh # if test -d "${SHARNESS_TEST_SRCDIR}/sharness.d" then for file in "${SHARNESS_TEST_SRCDIR}"/sharness.d/*.sh do # Ensure glob was not an empty match: test -e "${file}" || break if test -n "$debug" then echo >&5 "sharness: loading extensions from ${file}" fi . "${file}" if test $? != 0 then echo >&5 "sharness: Error loading ${file}. Aborting." exit 1 fi done fi # Public: Empty trash directory, the test area, provided for each test. The HOME # variable is set to that directory too. export SHARNESS_TRASH_DIRECTORY HOME="$SHARNESS_TRASH_DIRECTORY" export HOME mkdir -p "$SHARNESS_TRASH_DIRECTORY" || exit 1 # Use -P to resolve symlinks in our working directory so that the cwd # in subprocesses like git equals our $PWD (for pathname comparisons). cd -P "$SHARNESS_TRASH_DIRECTORY" || exit 1 for skp in $SKIP_TESTS; do case "$SHARNESS_TEST_NAME" in $skp) say_color info >&3 "skipping test $this_test altogether" skip_all="skip all tests in $this_test" test_done esac done test -n "$TEST_LONG" && test_set_prereq EXPENSIVE test -n "$TEST_INTERACTIVE" && test_set_prereq INTERACTIVE # Make sure this script ends with code 0 : # vi: set ts=4 sw=4 noet : powerman-2.4.4/t/simulators/000077500000000000000000000000001467035776500160425ustar00rootroot00000000000000powerman-2.4.4/t/simulators/baytech.c000066400000000000000000000570571467035776500176430ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* baytech.c - baytech simulator */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include "xread.h" static void usage(void); static void _noop_handler(int signum); static void _prompt_loop_rpc3_de(void); static void _prompt_loop_rpc28_nc(void); static void _prompt_loop_rpc3_nc(void); static void _prompt_loop_rpc3(void); typedef enum { NONE, RPC3, RPC3_NC, RPC28_NC, RPC3_DE } baytype_t; static char *prog; #define OPTIONS "p:" static const struct option longopts[] = { { "personality", required_argument, 0, 'p' }, {0, 0, 0, 0}, }; int main(int argc, char *argv[]) { int c; baytype_t personality = NONE; prog = basename(argv[0]); while ((c = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) { switch (c) { case 'p': if (strcmp(optarg, "rpc3") == 0) personality = RPC3; else if (strcmp(optarg, "rpc3-nc") == 0) personality = RPC3_NC; else if (strcmp(optarg, "rpc28-nc") == 0) personality = RPC28_NC; else if (strcmp(optarg, "rpc3-de") == 0) personality = RPC3_DE; else usage(); break; default: usage(); } } if (optind < argc) usage(); if (signal(SIGPIPE, _noop_handler) == SIG_ERR) { perror("signal"); exit(1); } switch (personality) { case NONE: usage(); case RPC3: _prompt_loop_rpc3(); break; case RPC3_NC: _prompt_loop_rpc3_nc(); break; case RPC28_NC: _prompt_loop_rpc28_nc(); break; case RPC3_DE: _prompt_loop_rpc3_de(); break; } exit(0); } static void usage(void) { fprintf(stderr, "Usage: %s -p rpc3|rpc3-nc|rpc28-nc|rpc3-de\n", prog); exit(1); } static void _noop_handler(int signum) { fprintf(stderr, "%s: received signal %d\n", prog, signum); } #define RPC28_NC_BANNER "\ RPC-28 Series\n\ (C) 2000 by BayTech\n\ F3.01\n\ \n\ Option(s) Installed:\n\ True RMS Current\n\ Internal Temperature\n\ True RMS Voltage\n\ \n" #define RPC28_NC_PROMPT "RPC-28>" #define RPC28_NC_PROMPT2 "RPC-28A>" #define RPC28_NC_STATUS "\r\n\ Outlet 1-10 Outlet 11-21 \r\n\ Average Power: 619 Watts : 5 Watts \r\n\ True RMS Voltage: 117.9 Volts : 118.8 Volts \r\n\ True RMS Current: 5.4 Amps : 0.1 Amps\r\n\ Maximum Detected: 6.9 Amps : 2.8 Amps\r\n\ Circuit Breaker: Good : Good \r\n\ \r\n\ Internal Temperature: 30.0 C\r\n\ \r\n\ \r\n\ 1)...Outlet 1 : %s 2)...Outlet 2 : %s \r\n\ 3)...Outlet 3 : %s 4)...Outlet 4 : %s \r\n\ 5)...Outlet 5 : %s 6)...Outlet 6 : %s \r\n\ 7)...Outlet 7 : %s 8)...Outlet 8 : %s \r\n\ 9)...Outlet 9 : %s 10)...Outlet 10 : %s \r\n\ 11)...Outlet 11 : %s 12)...Outlet 12 : %s \r\n\ 13)...Outlet 13 : %s 14)...Outlet 14 : %s \r\n\ 15)...Outlet 15 : %s 16)...Outlet 16 : %s \r\n\ 17)...Outlet 17 : %s 18)...Outlet 18 : %s \r\n\ 19)...Outlet 19 : %s 20)...Outlet 20 : %s \r\n\ \r\n\ Type \"Help\" for a list of commands\r\n\ \r\n" #define RPC28_NC_HELP "\r\n\ On n --Turn on an Outlet, n=0,1...20,all\r\n\ Off n --Turn off an Outlet, n=0,1...20,all\r\n\ Reboot n --Reboot an Outlet, n=0,1...20,all\r\n\ Status --RPC-28 Status\r\n\ Config --Enter configuration mode\r\n\ Lock n --Locks Outlet(s) state, n=0,1...20,all\r\n\ Unlock n --Unlock Outlet(s) state, n=0,1...20,all\r\n\ Current --Display True RMS Current\r\n\ Clear --Reset the maximum detected current\r\n\ Temp --Read current temperature\r\n\ Voltage --Display True RMS Voltage\r\n\ Logout --Logoff\r\n\ Logoff --Logoff\r\n\ Exit --Logoff\r\n\ Password --Changes the current user password\r\n\ Whoami --Displays the current user name\r\n\ Unitid --Displays the unit ID\r\n\ Help --This Command\r\n\ \r\n\ \r\n\ Type \"Help\" for a list of commands\r\n\ \r\n" #define RPC28_NC_TEMP "\r\n\ Internal Temperature: 30.0 C\r\n\ \r\n\ Type \"Help\" for a list of commands\r\n\ \r\n" #define RPC28_NC_VOLTAGE "\r\n\ Outlet 1-10 Outlet 11-21 \r\n\ True RMS Voltage: 118.0 Volts : 118.7 Volts \r\n\ \r\n\ Type \"Help\" for a list of commands\r\n\ \r\n" #define RPC28_NC_CURRENT "\r\n\ Outlet 1-10 Outlet 11-21 \r\n\ True RMS Current: 5.5 Amps : 0.1 Amps\r\n\ Maximum Detected: 6.9 Amps : 2.8 Amps\r\n\ \r\n\ Type \"Help\" for a list of commands\r\n\ \r\n" static void _prompt_loop_rpc28_nc(void) { int i; char buf[128]; int num_plugs = 20; char plug[20][4]; int plug_origin = 1; int logged_in = 1; int seq = 0; for (i = 0; i < num_plugs; i++) strcpy(plug[i], "Off"); printf(RPC28_NC_BANNER); while (logged_in) { /* switch between two possible prompts - our scripts must handle both */ if (xreadline((seq++ % 2) ? RPC28_NC_PROMPT : RPC28_NC_PROMPT2, buf, sizeof(buf)) == NULL) break; if (strlen(buf) == 0) { continue; } else if (!strcmp(buf, "logoff") || !strcmp(buf, "logout") || !strcmp(buf, "exit")) { break; } else if (!strcmp(buf, "help")) { printf(RPC28_NC_HELP); } else if (!strcmp(buf, "temp")) printf(RPC28_NC_TEMP); else if (!strcmp(buf, "voltage")) printf(RPC28_NC_VOLTAGE); else if (!strcmp(buf, "current")) printf(RPC28_NC_CURRENT); else if (!strcmp(buf, "status")) { printf(RPC28_NC_STATUS, plug[0], plug[1], plug[2], plug[3], plug[4], plug[5], plug[6], plug[7], plug[8], plug[9], plug[10], plug[11], plug[12], plug[13], plug[14], plug[15], plug[16], plug[17], plug[18], plug[19]); /* NOTE: we only support one plug at a time or all for on,off,reboot */ } else if (sscanf(buf, "on %d", &i) == 1) { if (i >= plug_origin && i < num_plugs + plug_origin) strcpy(plug[i - plug_origin], "On "); else if (i == 0) for (i = 0; i < num_plugs; i++) strcpy(plug[i], "On "); else goto err; } else if (sscanf(buf, "off %d", &i) == 1) { if (i >= plug_origin && i < num_plugs + plug_origin) strcpy(plug[i - plug_origin], "Off"); else if (i == 0) for (i = 0; i < num_plugs; i++) strcpy(plug[i], "Off"); else goto err; } else if (sscanf(buf, "reboot %d", &i) == 1) { /* if off, leaves it off */ if (i == 0 || (i >= plug_origin && i < num_plugs + plug_origin)) { printf("\r\nRebooting... "); for (i = 9; i >= 0; i--) { printf("%d", i); fflush(stdout); sleep(1); } printf("\r\n"); } else goto err; } else goto err; continue; err: printf("Input error\r\n\r\n"); } } #define RPC3_DE_BANNER "\r\n\r\n\ RPC-3/4(A)DE Series\r\n\ (C) 2004 BayTech\r\n\ F1.08\r\n\ \r\n\ Option(s) Installed:\r\n\ True RMS Voltage\r\n\ True RMS Current\r\n\ Internal Temperature\r\n\ \r\n" #define RPC3_DE_PROMPT "RPC-4>" #define RPC3_DE_STATUS "\r\n\ \r\n\ -------------------------------------------------------------------------------\r\n\ | Outlet | True RMS | Peak RMS | True RMS | Average | Volt- |\r\n\ | Group | Current | Current | Voltage | Power | Amps |\r\n\ -------------------------------------------------------------------------------\r\n\ | Outlet 1-4 | 1.8 Amps | 2.3 Amps | 122.5 Volts | 216 Watts | 220 VA |\r\n\ | Outlet 5-8 | 2.4 Amps | 5.0 Amps | 122.1 Volts | 269 Watts | 277 VA |\r\n\ -------------------------------------------------------------------------------\r\n\ \r\n\ Internal Temperature: 78.8 F\r\n\ \r\n\ Switch 1: Open 2: Open\r\n\ \r\n\ 1)...Outlet 1 : %s \r\n\ 2)...Outlet 2 : %s \r\n\ 3)...Outlet 3 : %s \r\n\ 4)...Outlet 4 : %s \r\n\ 5)...Outlet 5 : %s \r\n\ 6)...Outlet 6 : %s \r\n\ 7)...Outlet 7 : %s \r\n\ 8)...Outlet 8 : %s \r\n\ \r\n\ \r\n\ Type Help for a list of commands\r\n\ \r\n" #define RPC3_DE_HELP "\r\n\r\n\ On n --Turn on an Outlet, n=0,1...8,all\r\n\ Off n --Turn off an Outlet, n=0,1...8,all\r\n\ Reboot n --Reboot an Outlet, n=0,1...8,all\r\n\ Status --RPC-4 Status\r\n\ Config --Enter configuration mode\r\n\ RC --Powerup/watchdog reset counts\r\n\ Lock n --Locks Outlet(s) state, n=0,1...8,all\r\n\ Unlock n --Unlock Outlet(s) state, n=0,1...8,all\r\n\ Current --Display True RMS Current\r\n\ Voltage --Display True RMS Voltage\r\n\ Power --Display Average Power\r\n\ Clear --Reset the maximum detected current\r\n\ Temp --Read current temperature\r\n\ Logout --Logoff\r\n\ Logoff --Logoff\r\n\ Exit --Logoff\r\n\ Password --Changes the current user password\r\n\ Whoami --Displays the current user name\r\n\ Unitid --Displays the unit ID\r\n\ \r\n\ \r\n\ Type Help for a list of commands\r\n\ \r\n" #define RPC3_DE_TEMP "\r\n\r\n\ Internal Temperature: 77.9 F\r\n\ \r\n\ Type Help for a list of commands\r\n\ \r\n" #define RPC3_DE_VOLTAGE "\r\n\r\n\ --------------------------------\r\n\ | Outlet | True RMS |\r\n\ | Group | Voltage |\r\n\ --------------------------------\r\n\ | Outlet 1-4 | 122.4 Volts | \r\n\ | Outlet 5-8 | 122.3 Volts | \r\n\ --------------------------------\r\n\ \r\n\ Type Help for a list of commands\r\n\ \r\n" #define RPC3_DE_CURRENT "\r\n\r\n\ ------------------------------------------\r\n\ | Outlet | True RMS | Peak RMS |\r\n\ | Group | Current | Current |\r\n\ ------------------------------------------\r\n\ | Outlet 1-4 | 1.8 Amps | 2.3 Amps |\r\n\ | Outlet 5-8 | 2.3 Amps | 5.0 Amps |\r\n\ ------------------------------------------\r\n\ \r\n\ \r\n\ \r\n\ Type Help for a list of commands\r\n\ \r\n" #define RPC3_DE_POWER "\r\n\r\n\ ------------------------------------------\r\n\ | Outlet | True RMS | Peak RMS |\r\n\ | Group | Current | Current |\r\n\ ------------------------------------------\r\n\ | Outlet 1-4 | 1.8 Amps | 2.3 Amps |\r\n\ | Outlet 5-8 | 2.3 Amps | 5.0 Amps |\r\n\ ------------------------------------------\r\n\ \r\n\ \r\n\ \r\n\ Type Help for a list of commands\r\n\ \r\n" static void _prompt_loop_rpc3_de(void) { int i; char buf[128]; int num_plugs = 8; char plug[8][4]; int plug_origin = 1; int logged_in = 1; for (i = 0; i < num_plugs; i++) strcpy(plug[i], "Off"); printf(RPC3_DE_BANNER); while (logged_in) { if (xreadline(RPC3_DE_PROMPT, buf, sizeof(buf)) == NULL) break; if (strlen(buf) == 0) { continue; } else if (!strcmp(buf, "logoff") || !strcmp(buf, "logout") || !strcmp(buf, "exit")) { break; } else if (!strcmp(buf, "help")) { printf(RPC3_DE_HELP); } else if (!strcmp(buf, "temp")) printf(RPC3_DE_TEMP); else if (!strcmp(buf, "voltage")) printf(RPC3_DE_VOLTAGE); else if (!strcmp(buf, "current")) printf(RPC3_DE_CURRENT); else if (!strcmp(buf, "power")) printf(RPC3_DE_POWER); else if (!strcmp(buf, "status")) { printf(RPC3_DE_STATUS, plug[0], plug[1], plug[2], plug[3], plug[4], plug[5], plug[6], plug[7]); /* NOTE: we only support one plug at a time or all for on,off,reboot */ } else if (sscanf(buf, "on %d", &i) == 1) { if (i >= plug_origin && i < num_plugs + plug_origin) strcpy(plug[i - plug_origin], "On "); else if (i == 0) for (i = 0; i < num_plugs; i++) strcpy(plug[i], "On "); else goto err; } else if (sscanf(buf, "off %d", &i) == 1) { if (i >= plug_origin && i < num_plugs + plug_origin) strcpy(plug[i - plug_origin], "Off"); else if (i == 0) for (i = 0; i < num_plugs; i++) strcpy(plug[i], "Off"); else goto err; } else if (sscanf(buf, "reboot %d", &i) == 1) { /* if off, leaves it off */ if (i == 0 || (i >= plug_origin && i < num_plugs + plug_origin)) { printf("\r\nRebooting... "); for (i = 9; i >= 0; i--) { printf("%d", i); fflush(stdout); sleep(1); } printf("\r\n"); } else goto err; } else goto err; continue; err: printf("Input error\r\n\r\n"); } } #define RPC3_NC_BANNER "\r\n\ \r\n\ RPC3-NC Series\r\n\ (C) 2002 by BayTech\r\n\ F4.00\r\n\ \r\n\ Option(s) Installed:\r\n\ True RMS Current\r\n\ Internal Temperature\r\n\ True RMS Voltage\r\n\ \r\n" #define RPC3_NC_PROMPT "RPC3-NC>" #define RPC3_NC_STATUS "\r\n\ \r\n\ Average Power: 338 Watts\r\n\ True RMS Voltage: 120.9 Volts\r\n\ True RMS Current: 2.9 Amps\r\n\ Maximum Detected: 4.3 Amps\r\n\ Circuit Breaker: Good\r\n\ \r\n\ Internal Temperature: 40.0 C\r\n\ \r\n\ \r\n\ 1)...Outlet 1 : %s \r\n\ 2)...Outlet 2 : %s \r\n\ 3)...Outlet 3 : %s \r\n\ 4)...Outlet 4 : %s \r\n\ 5)...Outlet 5 : %s \r\n\ 6)...Outlet 6 : %s \r\n\ 7)...Outlet 7 : %s \r\n\ 8)...Outlet 8 : %s \r\n\ \r\n\ Type \"Help\" for a list of commands\r\n\ \r\n" #define RPC3_NC_HELP "\r\n\ On n --Turn on an Outlet, n=0,1...8,all\r\n\ Off n --Turn off an Outlet, n=0,1...8,all\r\n\ Reboot n --Reboot an Outlet, n=0,1...8,all\r\n\ Status --RPC3-NC Status\r\n\ Config --Enter configuration mode\r\n\ Lock n --Locks Outlet(s) state, n=0,1...8,all\r\n\ Unlock n --Unlock Outlet(s) state, n=0,1...8,all\r\n\ Current --Display True RMS Current\r\n\ Clear --Reset the maximum detected current\r\n\ Temp --Read current temperature\r\n\ Voltage --Display True RMS Voltage\r\n\ Logout --Logoff\r\n\ Logoff --Logoff\r\n\ Exit --Logoff\r\n\ Password --Changes the current user password\r\n\ Whoami --Displays the current user name\r\n\ Unitid --Displays the unit ID\r\n\ Help --This Command\r\n\ \r\n\ \r\n\ Type \"Help\" for a list of commands\r\n\ \r\n" #define RPC3_NC_TEMP "\r\n\ Internal Temperature: 38.5 C\r\n\ \r\n\ Type \"Help\" for a list of commands\r\n\ \r\n" #define RPC3_NC_VOLTAGE "\r\n\r\n\ True RMS Voltage: 120.5 Volts \r\n\ \r\n\ Type \"Help\" for a list of commands\r\n\ \r\n" #define RPC3_NC_CURRENT "\r\n\r\n\ True RMS Current: 2.9 Amps\r\n\ Maximum Detected: 4.3 Amps\r\n\ \r\n\ \r\n\ Type \"Help\" for a list of commands\r\n\ \r\n" static void _prompt_loop_rpc3_nc(void) { int i; char buf[128]; int num_plugs = 8; char plug[8][4]; int plug_origin = 1; int logged_in = 1; for (i = 0; i < num_plugs; i++) strcpy(plug[i], "Off"); printf(RPC3_NC_BANNER); while (logged_in) { if (xreadline(RPC3_NC_PROMPT, buf, sizeof(buf)) == NULL) break; if (strlen(buf) == 0) { continue; } else if (!strcmp(buf, "logoff") || !strcmp(buf, "logout") || !strcmp(buf, "exit")) { break; } else if (!strcmp(buf, "help")) { printf(RPC3_NC_HELP); } else if (!strcmp(buf, "temp")) printf(RPC3_NC_TEMP); else if (!strcmp(buf, "voltage")) printf(RPC3_NC_VOLTAGE); else if (!strcmp(buf, "current")) printf(RPC3_NC_CURRENT); else if (!strcmp(buf, "status")) { printf(RPC3_NC_STATUS, plug[0], plug[1], plug[2], plug[3], plug[4], plug[5], plug[6], plug[7]); /* NOTE: we only support one plug at a time or all for on,off,reboot */ } else if (sscanf(buf, "on %d", &i) == 1) { if (i >= plug_origin && i < num_plugs + plug_origin) strcpy(plug[i - plug_origin], "On "); else if (i == 0) for (i = 0; i < num_plugs; i++) strcpy(plug[i], "On "); else goto err; } else if (sscanf(buf, "off %d", &i) == 1) { if (i >= plug_origin && i < num_plugs + plug_origin) strcpy(plug[i - plug_origin], "Off"); else if (i == 0) for (i = 0; i < num_plugs; i++) strcpy(plug[i], "Off"); else goto err; } else if (sscanf(buf, "reboot %d", &i) == 1) { /* if off, leaves it off */ if (i == 0 || (i >= plug_origin && i < num_plugs + plug_origin)) { printf("\r\nRebooting... "); for (i = 9; i >= 0; i--) { printf("%d", i); fflush(stdout); sleep(1); } printf("\r\n"); } else goto err; } else goto err; continue; err: printf("Input error\r\n\r\n"); } } #define RPC3_PROMPT " RPC-3>" #define RPC3_WELCOME "\ \r\n\ \r\n\ \r\n\ RPC-3 Telnet Host\r\n\ Revision F 5.01, (C) 2001 \r\n\ Bay Technical Associates\r\n\ Unit ID: BT RPC3-20\r\n" #define RPC3_LOGIN "\ \r\n\ Enter password>" #define RPC3_BANNER "\ Option(s) installed:\r\n\ True RMS Current\r\n\ Internal Temperature\r\n\ \r\n\ \r\n" #define RPC3_MENU "\r\n\ RPC-3 Menu:\r\n\ \r\n\ 1)...Outlet Control\r\n\ 2)...Manage Users\r\n\ 3)...Configuration\r\n\ 4)...Unit Status\r\n\ 5)...Reset Unit\r\n\ 6)...Logout\r\n\ \r\n\ Enter Selection>" #define RPC3_OUTLET "\ True RMS current: 1.7 Amps\r\n\ Maximum Detected: 2.5 Amps\r\n\ \r\n\ Internal Temperature: 32.0 C\r\n\ \r\n\ Circuit Breaker: On \r\n\ \r\n\ Selection Outlet Outlet Power\r\n\ Number Name Number Status\r\n\ 1 Outlet 1 1 %s \r\n\ 2 Outlet 2 2 %s \r\n\ 3 Outlet 3 3 %s \r\n\ 4 Outlet 4 4 %s \r\n\ 5 Outlet 5 5 %s \r\n\ 6 Outlet 6 6 %s \r\n\ 7 Outlet 7 7 %s \r\n\ 8 Outlet 8 8 %s \r\n\ \r\n\ Type \"Help\" for a list of commands\r\n\ \r\n" #define RPC3_OUTLET_HELP "\ RPC3 Command Summary (F 5.01).\r\n\ \"n\" refers to Selection Number, as displayed in outlet status\r\n\ LOGOUT : terminate session\r\n\ OFF n : turn off outlet \"n\", do all for n = 0\r\n\ ON n : turn on outlet \"n\", do all for n = 0\r\n\ REBOOT n : cycle power off/on outlet \"n\", do all for n = 0\r\n\ RC : display outlet relay control info\r\n\ STATUS : display power status of outlets\r\n\ HELP : display this message\r\n\ CLEAR : Reset the maximum detected current\r\n\ CURRENT : Read the current\r\n\ TEMP : Read current temperature\r\n\ MENU : return to main menu\r\n\ \r\n\ " static void _prompt_loop_rpc3(void) { int i; char buf[128]; int num_plugs = 8; char plug[8][4]; int plug_origin = 1; enum { START, MENU, OUTLET, QUIT } state = START; char *prompt = NULL; for (i = 0; i < num_plugs; i++) strcpy(plug[i], "Off"); printf(RPC3_WELCOME); while (state != QUIT) { switch (state) { case START: prompt = RPC3_LOGIN; break; case MENU: prompt = RPC3_MENU; break; case OUTLET: printf(RPC3_OUTLET, plug[0], plug[1], plug[2], plug[3], plug[4], plug[5], plug[6], plug[7]); prompt = RPC3_PROMPT; break; case QUIT: break; } if (xreadline(prompt, buf, sizeof(buf)) == NULL) { state = QUIT; continue; } switch (state) { case START: if (!strcmp(buf, "baytech")) { printf(RPC3_BANNER); state = MENU; } else printf(" Invalid password.\r\n\r\n"); break; case MENU: if (!strcmp(buf, "1")) state = OUTLET; else if (!strcmp(buf, "6")) state = QUIT; else goto err; break; case OUTLET: if (!strcmp(buf, "?") || !strcmp(buf, "help")) { if (xreadline(RPC3_OUTLET_HELP, buf, sizeof(buf)) == NULL) state = QUIT; } else if (!strcmp(buf, "menu")) { state = MENU; } else if (!strcmp(buf, "logout")) { state = QUIT; } else if (!strcmp(buf, "status")) { } else if (sscanf(buf, "on %d", &i) == 1) { if (i >= plug_origin && i < num_plugs + plug_origin) strcpy(plug[i - plug_origin], "On "); else if (i == 0) for (i = 0; i < num_plugs; i++) strcpy(plug[i], "On "); else goto err; } else if (sscanf(buf, "off %d", &i) == 1) { if (i >= plug_origin && i < num_plugs + plug_origin) strcpy(plug[i - plug_origin], "Off"); else if (i == 0) for (i = 0; i < num_plugs; i++) strcpy(plug[i], "Off"); else goto err; } else goto err; break; case QUIT: break; } continue; err: printf("\r\n Input error.\r\n\r\n"); } } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/t/simulators/cyclades.c000066400000000000000000000325311467035776500200010ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* cyclades.c - simulate cyclades power controllers */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include "xread.h" static void usage(void); static void _noop_handler(int signum); static void _prompt_loop(void); typedef enum { NONE, PM8, PM10, PM20, PM42 } cytype_t; static char *prog; static cytype_t personality = NONE; #define OPTIONS "p:" static const struct option longopts[] = { { "personality", required_argument, 0, 'p' }, {0, 0, 0, 0}, }; int main(int argc, char *argv[]) { int c; prog = basename(argv[0]); while ((c = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) { switch (c) { case 'p': if (strcmp(optarg, "pm8") == 0) personality = PM8; else if (strcmp(optarg, "pm10") == 0) personality = PM10; else if (strcmp(optarg, "pm20") == 0) personality = PM20; else if (strcmp(optarg, "pm42") == 0) personality = PM42; else usage(); break; default: usage(); } } if (optind < argc) usage(); if (personality == NONE) usage(); if (signal(SIGPIPE, _noop_handler) == SIG_ERR) { perror("signal"); exit(1); } _prompt_loop(); exit(0); } static void usage(void) { fprintf(stderr, "Usage: %s -p pm8|pm10|pm20|pm42\n", prog); exit(1); } static void _noop_handler(int signum) { fprintf(stderr, "%s: received signal %d\n", prog, signum); } #define BANNER "\ AlterPath PM\n\ Copyright (c) 2002-2003 Cyclades Corporation\n\ V 1.0.9a Jun 26, 2003\n\n" #define BANNER2 "\ AlterPath PM\n\ Copyright (c) 2007 Avocent Corporation\n\ V 1.9.1 May 2, 2007\n\ [PM]: IPDU: 1\n\ [PM]: OUT: 42\n" #define USER_PROMPT "Username: " /* admin */ #define PASS_PROMPT "Password: " /* pm8 */ #define CMD_PROMPT "pm>" #define FAILED_MSG "\nAuthentication failed.\n" #define HELP_MSG "\n\n\n\ Available commands:\n\ \n\ adduser alarm assign buzzer current\n\ cycle deluser factory_defaults help\n\ list lock name off on\n\ passwd reboot restore save status\n\ syslog unassign unlock ver whoami\n\ \n\ NOTE: To get detailed help on the commands listed above type\n\ ' help';\n\ NOTE: Some commands accept as input a data type called \n\ . is a string representing\n\ one or more outlets. This string can be:\n\ - one single outlet.\n\ Examples: on 3 (turn on outlet 3);\n\ off router (turn off the outlet called router).\n\ - a group of outlets.\n\ Examples: status 1,3,5 (get status of outlets 1, 3 and 5);\n\ cycle 2-7 (cycle the outlets 2, 3, 4, 5, 6, 7)\n\ lock 2,5-7 (lock the outlets 2, 5, 6 and 7).\n" #define HELP_MSG2 "\n\ Available commands:\n\ \n\ adduser alarm assign \n\ buzzer current currentprotection\n\ currseg cycle dbsync \n\ deluser display exit \n\ factory_defaults help hwocp \n\ humidity id interval \n\ list lock name \n\ off on outcycledelay \n\ passwd reboot restore \n\ save status syslog \n\ temperature unassign unlock \n\ upgrade ver voltage \n\ whoami \n\ \n\ NOTE: To get detailed help on the commands listed above type\n\ ' help'\n\n" #define STATUS_TMPL_PM8 "\ Outlet Name Status Users\n\ 1 Unlocked %s\n\ 2 Unlocked %s\n\ 3 Unlocked %s\n\ 4 Unlocked %s\n\ 5 Unlocked %s\n\ 6 Unlocked %s\n\ 7 Unlocked %s\n\ 8 Unlocked %s\n" #define STATUS_TMPL_PM10 "\ Outlet Name Status Users\n\ 1 Unlocked %s\n\ 2 Unlocked %s\n\ 3 Unlocked %s\n\ 4 Unlocked %s\n\ 5 Unlocked %s\n\ 6 Unlocked %s\n\ 7 Unlocked %s\n\ 8 Unlocked %s\n\ 9 Unlocked %s\n\ 10 Unlocked %s\n" #define STATUS_TMPL_PM20 "\ Outlet Name Status Users\n\ 1 Unlocked %s\n\ 2 Unlocked %s\n\ 3 Unlocked %s\n\ 4 Unlocked %s\n\ 5 Unlocked %s\n\ 6 Unlocked %s\n\ 7 Unlocked %s\n\ 8 Unlocked %s\n\ 9 Unlocked %s\n\ 10 Unlocked %s\n\ 11 Unlocked %s\n\ 12 Unlocked %s\n\ 13 Unlocked %s\n\ 14 Unlocked %s\n\ 15 Unlocked %s\n\ 16 Unlocked %s\n\ 17 Unlocked %s\n\ 18 Unlocked %s\n\ 19 Unlocked %s\n\ 20 Unlocked %s\n" #define STATUS_TMPL_PM42 "\ Outlet Name Status Interval (s) Users\n\ 1 Unlocked %s 0.0\n\ 2 Unlocked %s 0.0\n\ 3 Unlocked %s 0.0\n\ 4 Unlocked %s 0.0\n\ 5 Unlocked %s 0.0\n\ 6 Unlocked %s 0.0\n\ 7 Unlocked %s 0.0\n\ 8 Unlocked %s 0.0\n\ 9 Unlocked %s 0.0\n\ 10 Unlocked %s 0.0\n\ 11 Unlocked %s 0.0\n\ 12 Unlocked %s 0.0\n\ 13 Unlocked %s 0.0\n\ 14 Unlocked %s 0.0\n\ 15 Unlocked %s 0.0\n\ 16 Unlocked %s 0.0\n\ 17 Unlocked %s 0.0\n\ 18 Unlocked %s 0.0\n\ 19 Unlocked %s 0.0\n\ 20 Unlocked %s 0.0\n\ 21 Unlocked %s 0.0\n\ 22 Unlocked %s 0.0\n\ 23 Unlocked %s 0.0\n\ 24 Unlocked %s 0.0\n\ 25 Unlocked %s 0.0\n\ 26 Unlocked %s 0.0\n\ 27 Unlocked %s 0.0\n\ 28 Unlocked %s 0.0\n\ 29 Unlocked %s 0.0\n\ 30 Unlocked %s 0.0\n\ 31 Unlocked %s 0.0\n\ 32 Unlocked %s 0.0\n\ 33 Unlocked %s 0.0\n\ 34 Unlocked %s 0.0\n\ 35 Unlocked %s 0.0\n\ 36 Unlocked %s 0.0\n\ 37 Unlocked %s 0.0\n\ 38 Unlocked %s 0.0\n\ 39 Unlocked %s 0.0\n\ 40 Unlocked %s 0.0\n\ 41 Unlocked %s 0.0\n\ 42 Unlocked %s 0.0\n" #define CURRENT_PM42 "\ IPDU #1: RMS current for phase X: 2.3A. Maximum current for phase X: 10.8A\n\ IPDU #1: RMS current for phase Y: 0.0A. Maximum current for phase Y: 11.6A\n\ IPDU #1: RMS current for phase Z: 2.5A. Maximum current for phase Z: 11.0A\n" #define OFF_MSG "%d: Outlet turned off.\n" #define ON_MSG "%d: Outlet turned on.\n" static void _prompt_loop(void) { int i; char buf[128]; int num_plugs = 0; char plug[42][4]; int plug_origin = 1; char user[32], pass[32]; char status_all[32]; char on_all[32]; char off_all[32]; switch (personality) { case PM8: num_plugs = 8; break; case PM10: num_plugs = 10; break; case PM20: num_plugs = 20; break; case PM42: num_plugs = 42; break; case NONE: num_plugs = 0; } snprintf(status_all, sizeof(status_all), "status 1-%d", num_plugs); snprintf(on_all, sizeof(on_all), "on 1-%d", num_plugs); snprintf(off_all, sizeof(off_all), "off 1-%d", num_plugs); for (i = 0; i < num_plugs; i++) strcpy(plug[i], "OFF"); login_again: printf(personality == PM42 ? BANNER2 : BANNER); do { if (xreadline(USER_PROMPT, user, sizeof(user)) == NULL) goto done; if (xreadline(PASS_PROMPT, pass, sizeof(pass)) == NULL) goto done; } while (strcmp(user, "admin") != 0 || strcmp(pass, "pm8") != 0); while (1) { if (xreadline(CMD_PROMPT, buf, sizeof(buf)) == NULL) { goto done; } else if (strlen(buf) == 0) { continue; } else if (!strcmp(buf, "exit")) { sleep(1); goto login_again; } else if (!strcmp(buf, "help")) { printf(personality == PM42 ? HELP_MSG2 : HELP_MSG); } else if (!strcmp(buf, status_all)) { if (personality == PM8) { printf(STATUS_TMPL_PM8, plug[0], plug[1], plug[2], plug[3], plug[4], plug[5], plug[6], plug[7]); } else if (personality == PM10) { printf(STATUS_TMPL_PM10, plug[0], plug[1], plug[2], plug[3], plug[4], plug[5], plug[6], plug[7], plug[8], plug[9]); } else if (personality == PM20) { printf(STATUS_TMPL_PM20, plug[0], plug[1], plug[2], plug[3], plug[4], plug[5], plug[6], plug[7], plug[8], plug[9], plug[10], plug[11], plug[12], plug[13], plug[14], plug[15], plug[16], plug[17], plug[18], plug[19]); } else if (personality == PM42) { printf(STATUS_TMPL_PM42, plug[0], plug[1], plug[2], plug[3], plug[4], plug[5], plug[6], plug[7], plug[8], plug[9], plug[10], plug[11], plug[12], plug[13], plug[14], plug[15], plug[16], plug[17], plug[18], plug[19], plug[20], plug[21], plug[22], plug[23], plug[24], plug[25], plug[26], plug[27], plug[28], plug[29], plug[30], plug[31], plug[32], plug[33], plug[34], plug[35], plug[36], plug[37], plug[38], plug[39], plug[40], plug[41]); } } else if (!strcmp(buf, on_all)) { for (i = 0; i < num_plugs; i++) { strcpy(plug[i], personality == PM42 ? "ON " : "ON"); printf(ON_MSG, i); } } else if (sscanf(buf, "on %d", &i) == 1) { if (i >= plug_origin && i < num_plugs + plug_origin) { strcpy(plug[i - plug_origin], personality == PM42 ? "ON ":"ON"); printf(ON_MSG, i); } else goto err; } else if (!strcmp(buf, off_all)) { for (i = 0; i < num_plugs; i++) { strcpy(plug[i], "OFF"); printf(OFF_MSG, i); } } else if (sscanf(buf, "off %d", &i) == 1) { if (i >= plug_origin && i < num_plugs + plug_origin) { strcpy(plug[i - plug_origin], "OFF"); printf(OFF_MSG, i); } else goto err; } else goto err; continue; err: printf("Input error\r\n\r\n"); } done: return; } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/t/simulators/dli.c000066400000000000000000000172741467035776500167710ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* dli.c - mimic httppower talking to a Digital Loggers Inc LPC */ #include #include #include #include #include "xread.h" #define DLI_POST "\ \n\ \n\ \n\ \n\ \n" #define DLI_GET "\ \n\ \n\ \n\ \n\ Outlet Control - Lite Power Controller\n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\
\n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\
\n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\
\n\ \n\
Ethernet Power Controller
\n\
\n\
Outlet Control
Setup
AutoPing
Logout
Help

Link 1
Link 2
Link 3
Link 4
\n\
\n\ Version 1.2.1 (Aug 23 2007 / 20:14:33) 1555A5A1-D43E3FC2\n\
\n\ S/N:0000130175\n\
\n\ \n\ \n\
\n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\
\n\ Controller: Lite Power Controller\n\
\n\ Uptime: 0:35:01 \n\
\n\ \n\ \n\
\n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\
\n\ Individual Control\n\
#NameStateAction
1Outlet 1\n\ %s\n\ Switch ON\n\ \n\ \n\
2Outlet 2\n\ %s\n\ Switch ON\n\ \n\ \n\
3Outlet 3\n\ %s\n\ Switch ON\n\ \n\ \n\
4Outlet 4\n\ %s\n\ Switch ON\n\ \n\ \n\
5Outlet 5\n\ %s\n\ Switch ON\n\ \n\ \n\
6Outlet 6\n\ %s\n\ Switch ON\n\ \n\ \n\
7Outlet 7\n\ %s\n\ Switch ON\n\ \n\ \n\
8Outlet 8\n\ %s\n\ Switch ON\n\ \n\ \n\
\n\ \n\ \n\
\n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\
Master Control
All outlets OFF
All outlets ON
Cycle all outlets
Sequence delay: 1 sec.
\n\ \n\ \n\
\n\ \n\ \n\ \n" static void prompt_loop(void) { char buf[128], tmp[32]; char plug[8][4]; int num_plugs = 8; int plug_origin = 1; int i; int authenticated = 0; for (i = 0; i < num_plugs; i++) strcpy(plug[i], "OFF"); for (;;) { if (xreadline("httppower> ", buf, sizeof(buf)) == NULL) break; if (!strcmp(buf, "help")) { printf("Commands are:\n"); printf(" auth admin:admin\n"); printf(" get\n"); printf(" post outlet [1-8]=ON|OFF\n"); } else if (!strcmp(buf, "auth admin:admin")) { authenticated = 1; } else if (!strcmp(buf, "get")) { if (!authenticated) goto err; printf(DLI_GET, plug[0], plug[1], plug[2], plug[3], plug[4], plug[5], plug[6], plug[7]); } else if (sscanf(buf, "post outlet %d=%s", &i, tmp) == 2) { if (!authenticated) goto err; if (i < plug_origin || i >= num_plugs + plug_origin) goto err; if (!strcmp(tmp, "ON")) strcpy(plug[i - plug_origin], "ON"); else if (!strcmp(tmp, "OFF")) strcpy(plug[i - plug_origin], "OFF"); else goto err; printf(DLI_POST); } else goto err; continue; err: printf("Error\n"); } } int main(int argc, char *argv[]) { prompt_loop(); exit (0); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/t/simulators/icebox.c000066400000000000000000000147561467035776500174740ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* icebox.c - icebox simulator */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include "xread.h" static void usage(void); static void _noop_handler(int signum); static void _prompt_loop(void); typedef enum { NONE, V2, V3, V4 } icetype_t; static icetype_t personality = NONE; static char *prog; #define OPTIONS "p:" static const struct option longopts[] = { { "personality", required_argument, 0, 'p' }, {0, 0, 0, 0}, }; int main(int argc, char *argv[]) { int c; prog = basename(argv[0]); while ((c = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) { switch (c) { case 'p': if (strcmp(optarg, "v2") == 0) personality = V2; else if (strcmp(optarg, "v3") == 0) personality = V3; else if (strcmp(optarg, "v4") == 0) personality = V4; else usage(); break; default: usage(); } } if (optind < argc) usage(); if (personality == NONE) usage(); if (signal(SIGPIPE, _noop_handler) == SIG_ERR) { perror("signal"); exit(1); } _prompt_loop(); exit(0); } static void usage(void) { fprintf(stderr, "Usage: %s -p v2|v3|v4\n", prog); exit(1); } static void _noop_handler(int signum) { fprintf(stderr, "%s: received signal %d\n", prog, signum); } #define V2_BANNER "V2.1\r\n" #define V3_BANNER "V3.0\r\n" #define V4_BANNER "V4.0\r\n" #define V3_AUTHCMD "auth icebox\r\n" #define V3_RESP_OK "OK\r\n" #define V3_ERROR_CMD "ERROR 0\r\n" #define V3_ERROR_AUTH "ERROR 4\r\n" #define V3_POWER_STATUS "\ N1:%d N2:%d N3:%d N4:%d N5:%d N6:%d N7:%d N8:%d N9:%d N10:%d\r\n" #define V3_BEACON_STATUS "\ N1:%s N2:%s N3:%s N4:%s N5:%s N6:%s N7:%s N8:%s N9:%s N10:%s N11:%s N12:%s\r\n" #define V2_TEMP "\ N1:%d,0,0,0 N2:%d,0,0,0 N3:%d,0,0,0 N4:%d,0,0,0 N5:%d,0,0,0 N6:%d,0,0,0 N7:%d,0,0,0 N8:%d,0,0,0 N9:%d,0,0,0 N10:%d,0,0,0 N11:%d,0,0,0 N12:%d,0,0,0\r\n" #define V3_TEMP "\ N1:%d: N2:%d: N3:%d: N4:%d: N5:%d: N6:%d: N7:%d: N8:%d: N9:%d: N10:%d: N11:%d: N12:%d:\r\n" static void _prompt_loop(void) { int i; char buf[128]; int num_plugs = 10; int num_plugs_ext = 12; int plug[12]; char beacon[12][4]; int temp[12]; int plug_origin = 1; int logged_in = 0; char arg[80]; for (i = 0; i < num_plugs_ext; i++) { plug[i] = 0; temp[i] = 73 + i; strcpy(beacon[i], "OFF"); } /* User must first authenticate. */ switch (personality) { case V2: printf(V2_BANNER); break; case V3: printf(V3_BANNER); break; case V4: printf(V4_BANNER); break; case NONE: break; } while (!logged_in) { if (xreadline("", buf, sizeof(buf)) == NULL) return; if (strcmp(buf, "auth icebox") == 0) { logged_in = 1; printf(V3_RESP_OK); } else printf(V3_ERROR_AUTH); } /* Process commands. */ while (logged_in) { if (xreadline("", buf, sizeof(buf)) == NULL) break; if (strlen(buf) == 0) { goto err; } else if (!strcmp(buf, "q")) { logged_in = 0; } else if (!strcmp(buf, "ps *") || !strcmp(buf, "ns *")) { printf(V3_POWER_STATUS, plug[0], plug[1], plug[2], plug[3], plug[4], plug[5], plug[6], plug[7], plug[8], plug[9]); } else if (personality != V2 && !strcmp(buf, "be *")) { printf(V3_BEACON_STATUS, beacon[0], beacon[1], beacon[2], beacon[3], beacon[4], beacon[5], beacon[6], beacon[7], beacon[8], beacon[9], beacon[10], beacon[11]); } else if (personality != V2 && !strcmp(buf, "is *")) { printf(V3_TEMP, temp[0], temp[1], temp[2], temp[3], temp[4], temp[5], temp[6], temp[7], temp[8], temp[9], temp[10], temp[11]); } else if (personality == V2 && !strcmp(buf, "ts *")) { printf(V2_TEMP, temp[0], temp[1], temp[2], temp[3], temp[4], temp[5], temp[6], temp[7], temp[8], temp[9], temp[10], temp[11]); } else if (!strcmp(buf, "ph *")) { for (i = 0; i < num_plugs; i++) plug[i] = 1; } else if (sscanf(buf, "ph %d", &i) == 1) { if (i >= plug_origin && i < num_plugs + plug_origin) plug[i - plug_origin] = 1; else goto err; } else if (!strcmp(buf, "pl *")) { for (i = 0; i < num_plugs; i++) plug[i] = 0; } else if (sscanf(buf, "pl %d", &i) == 1) { if (i >= plug_origin && i < num_plugs + plug_origin) plug[i - plug_origin] = 0; else goto err; } else if (!strcmp(buf, "rp *")) { } else if (sscanf(buf, "rp %d", &i) == 1) { if (!(i >= plug_origin && i < num_plugs + plug_origin)) goto err; } else if (personality != V2 && sscanf(buf, "be %d %s", &i, arg) == 2) { if (i >= plug_origin && i < num_plugs_ext + plug_origin) { if (!strcmp(arg, "off")) strcpy(beacon[i - plug_origin], "OFF"); else if (!strcmp(arg, "on")) strcpy(beacon[i - plug_origin], "ON"); else goto err; } else goto err; } else goto err; if (logged_in) printf(V3_RESP_OK); continue; err: printf(V3_ERROR_CMD); } } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/t/simulators/ilom.c000066400000000000000000000144101467035776500171460ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include "xread.h" #define ILOM_LOGIN_PROMPT "SUNSP00144FEE320F login: " #define ILOM_PASSWD_PROMPT "Password: " #define ILOM_PROMPT " -> " #define ILOM_BANNER "\n\ Sun(TM) Integrated Lights Out Manager\n\ \n\ Version 2.0.2.3\n\ \n\ Copyright 2007 Sun Microsystems, Inc. All rights reserved.\n\ Use is subject to license terms.\n\ \n\ Warning: password is set to factory default.\n\n" #define ILOM_PROP_SYS "\ /SYS\n\ Properties:\n\ type = Host System\n\ chassis_name = SUN FIRE X4140\n\ chassis_part_number = 540-7618-XX\n\ chassis_serial_number = 0226LHF-0823A600HM\n\ chassis_manufacturer = SUN MICROSYSTEMS\n\ product_name = SUN FIRE X4140\n\ product_part_number = 602-4125-01\n\ product_serial_number = 0826QAD075\n\ product_manufacturer = SUN MICROSYSTEMS\n\ power_state = %s\n\n\n" #define ILOM_STOP_RESP "Stopping /SYS immediately\n\n" #define ILOM_STOP_RESP2 "stop: Target already stopped\n\n" #define ILOM_START_RESP "Starting /SYS\n\n" #define ILOM_START_RESP2 "start: Target already started\n\n" #define ILOM_RESET_RESP "Performing hard reset on /SYS\n\n" #define ILOM_RESET_RESP2 "Performing hard reset on /SYS failed\n\ reset: Target already stopped\n\n" #define ILOM_CMD_INVAL "\ Invalid command '%s' - type help for a list of commands.\n\n" #define ILOM_HELP "\ The help command is used to view information about commands and targets\n\ \n\ Usage: help [-o|-output terse|verbose] [|legal|targets]\n\ \n\ Special characters used in the help command are\n\ [] encloses optional keywords or options\n\ <> encloses a description of the keyword\n\ (If <> is not present, an actual keyword is indicated)\n\ | indicates a choice of keywords or options\n\ \n\ help targets displays a list of targets\n\ help legal displays the product legal notice\n\ \n\ Commands are:\n\ cd\n\ create\n\ delete\n\ exit\n\ help\n\ load\n\ reset\n\ set\n\ show\n\ start\n\ stop\n\ version\n\n" #define ILOM_VERS "\ SP firmware 2.0.2.3\n\ SP firmware build number: 29049\n\ SP firmware date: Thu Feb 21 19:42:30 PST 2008\n\ SP filesystem version: 0.1.16\n\n" static void usage(void); static void prompt_loop(void); typedef enum { NONE, SSH, SER, SER_LOGIN } ilomtype_t; static ilomtype_t personality = NONE; static char *prog; #define OPTIONS "p:" static const struct option longopts[] = { { "personality", required_argument, 0, 'p' }, {0, 0, 0, 0}, }; int main(int argc, char *argv[]) { int c; prog = basename(argv[0]); while ((c = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) { switch (c) { case 'p': if (strcmp(optarg, "ssh") == 0) personality = SSH; else if (strcmp(optarg, "serial") == 0) personality = SER; else if (strcmp(optarg, "serial_loggedin") == 0) personality = SER_LOGIN; else usage(); break; default: usage(); } } if (optind < argc) usage(); if (personality == NONE) usage(); prompt_loop(); exit(0); } static void usage(void) { fprintf(stderr, "Usage: %s -p ssh|serial|serial_loggedin\n", prog); exit(1); } static void prompt_loop(void) { char buf[128]; static char plug[4]; int authenticated = 0; strcpy(plug, "Off"); switch (personality) { case SER: authenticated = 0; break; case SSH: authenticated = 1; break; case SER_LOGIN: authenticated = 2; break; case NONE: authenticated = 0; } for (;;) { switch (authenticated) { case 0: if (xreadline(ILOM_LOGIN_PROMPT, buf, sizeof(buf)) == NULL) goto done; if (!strcmp(buf, "root")) authenticated = 1; break; case 1: if (xreadline(ILOM_PASSWD_PROMPT, buf, sizeof(buf)) == NULL) goto done; if (!strcmp(buf, "changeme")) { authenticated = 2; printf(ILOM_BANNER); } break; case 2: if (xreadline(ILOM_PROMPT, buf, sizeof(buf)) == NULL) goto done; if (!strcmp(buf, "exit")) { goto done; } else if (!strcmp(buf, "help")) { printf(ILOM_HELP); } else if (!strcmp(buf, "version")) { printf(ILOM_VERS); } else if (!strcmp(buf, "show -d properties /SYS")) { printf(ILOM_PROP_SYS, plug); } else if (!strcmp(buf, "start -script /SYS")) { if (!strcmp(plug, "Off")) { strcpy(plug, "On"); printf(ILOM_START_RESP); } else printf(ILOM_START_RESP2); } else if (!strcmp(buf, "stop -script -force /SYS")) { if (!strcmp(plug, "On")) { strcpy(plug, "Off"); printf(ILOM_STOP_RESP); } else printf(ILOM_STOP_RESP2); } else if (!strcmp(buf, "reset -script /SYS")) { if (!strcmp(plug, "On")) { printf(ILOM_RESET_RESP); } else printf(ILOM_RESET_RESP2); } else { printf(ILOM_CMD_INVAL, buf); } } continue; done: break; } } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/t/simulators/ipmipower.c000066400000000000000000000160511467035776500202240ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* ipmipower.c - simulate FreeIPMI ipmipower */ /* achu: I'm not supporting a full-fledged ipmipower, there are over * 20 different configurations you can set (via cmdline, prompt, and * config file) and 7 power control commands (on, off, stat, cycle, * reset, pulse, soft). Many of the commands accepts all, hostrange, * or single host. * * Assumptions: * * Users configure ipmipower authentication via FreeIPMI's * configuration file. So there is no ipmipower authentication * configuration via powerman. Thus, I assume there is no need for * those configuration capabilities in this simulator (cmdline, config * file, or prompt). * * Users configure hostnames via cmdline in the powerman.conf. So we * support the -h/--hostname option on the command line, but not * anywhere else. * * powerman's ipmipower.dev only utilizes on, off, and stat in * ipmipower. So we only support those power control commands in the * command line prompt of this simulator (not on the cmdline). */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include "hash.h" #include "hostlist.h" #include "xread.h" static void usage(void); static void _noop_handler(int signum); static void _prompt_loop(void); static char *prog; static char *hostname = NULL; static int auth_failure = 0; #define OPTIONS "h:A" static const struct option longopts[] = { { "hostname", required_argument, 0, 'h' }, { "auth-failure", no_argument, 0, 'A' }, {0, 0, 0, 0}, }; int main(int argc, char *argv[]) { int c; prog = basename(argv[0]); while ((c = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) { switch (c) { case 'h': hostname = optarg; break; case 'A': auth_failure = 1; break; default: usage(); } } if (optind < argc) usage(); if (hostname == NULL) usage(); if (signal(SIGPIPE, _noop_handler) == SIG_ERR) { perror("signal"); exit(1); } _prompt_loop(); exit(0); } static void usage(void) { fprintf(stderr, "Usage: %s -h hostlist\n", prog); exit(1); } static void _noop_handler(int signum) { fprintf(stderr, "%s: received signal %d\n", prog, signum); } #define CMD_PROMPT "ipmipower> " #define OFF_STATUS "off" #define ON_STATUS "on" #define OK_STATUS "ok" #define HASH_SIZE 1024 static void _stat(hash_t hstatus, const char *nodes) { hostlist_iterator_t hlitr; hostlist_t hlnodes; char *node; char *str; assert(hstatus); if (!(hlnodes = hostlist_create(nodes))) { perror("hostlist_create"); exit(1); } if (!(hlitr = hostlist_iterator_create(hlnodes))) { perror("hostlist_iterator_create"); exit(1); } while ((node = hostlist_next(hlitr))) { if ((str = hash_find(hstatus, node))) { if (auth_failure) { /* github issue #14 * The error string contains "on". * Ideally we want to return "unknown" state without delay. */ printf ("%s: %s\n", node, "password verification timeout"); auth_failure = 0; } else printf("%s: %s\n", node, str); } else printf("%s: %s\n", node, "invalid hostname"); free(node); } hostlist_iterator_destroy(hlitr); hostlist_destroy(hlnodes); } static void _onoff(hash_t hstatus, const char *nodes, const char *state) { hostlist_iterator_t hlitr; hostlist_t hlnodes; char *node; char *str; assert(hstatus); if (!(hlnodes = hostlist_create(nodes))) { perror("hostlist_create"); exit(1); } if (!(hlitr = hostlist_iterator_create(hlnodes))) { perror("hostlist_iterator_create"); exit(1); } while ((node = hostlist_next(hlitr))) { if ((str = hash_find(hstatus, node))) { printf("%s: %s\n", node, OK_STATUS); hash_remove(hstatus, node); if (!hash_insert(hstatus, (void *)node, (void *)state)) { perror("hash_insert"); exit(1); } /* XXX: Don't free 'node' here, it needs to be alloc'd for * the hash key. It's a mem-leak. Fix later. */ } else { printf("%s: %s\n", node, "invalid hostname"); free(node); } } hostlist_iterator_destroy(hlitr); hostlist_destroy(hlnodes); } static void _prompt_loop(void) { char buf[128]; char bufnode[128]; hash_t hstatus = NULL; hostlist_t hl = NULL; hostlist_iterator_t hlitr = NULL; char *node; assert(hostname); if (!(hstatus = hash_create(HASH_SIZE, (hash_key_f)hash_key_string, (hash_cmp_f)strcmp, (hash_del_f)NULL))) { perror("hash_create"); exit(1); } if (!(hl = hostlist_create(hostname))) { perror("hostlist_create"); exit(1); } if (!(hlitr = hostlist_iterator_create(hl))) { perror("hostlist_iterator"); exit(1); } /* all nodes begin as off */ while ((node = hostlist_next(hlitr))) { if (!hash_insert(hstatus, (void *)node, OFF_STATUS)) { perror("hash_insert"); exit(1); } /* XXX: Don't free 'node' here, it needs to be alloc'd for * the hash key. It's a mem-leak. Fix later. */ } hostlist_iterator_destroy(hlitr); hostlist_destroy(hl); while (1) { if (xreadline(CMD_PROMPT, buf, sizeof(buf)) == NULL) { break; } else if (strlen(buf) == 0) { continue; } else if (!strcmp(buf, "quit")) { break; } else if (!strcmp(buf, "stat")) { _stat(hstatus, hostname); } else if (sscanf(buf, "stat %s", bufnode) == 1) { _stat(hstatus, bufnode); } else if (!strcmp(buf, "on")) { _onoff(hstatus, hostname, ON_STATUS); } else if (sscanf(buf, "on %s", bufnode) == 1) { _onoff(hstatus, bufnode, ON_STATUS); } else if (!strcmp(buf, "off")) { _onoff(hstatus, hostname, OFF_STATUS); } else if (sscanf(buf, "off %s", bufnode) == 1) { _onoff(hstatus, bufnode, OFF_STATUS); } else printf("unknown command - type \"help\"\n"); } hash_destroy(hstatus); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/t/simulators/lom.c000066400000000000000000000100321467035776500167710ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include "xread.h" #define LOM_LOGIN_PROMPT "SUNSP00144FEE320F login: " #define LOM_PASSWD_PROMPT "admin@paradise-sp's password: " #define LOM_PROMPT "paradise $ " #define LOM_BANNER "\n\ Sun Microsystems\n\ IPMI v1.5 Service Processor\n\ \n\ Version: V2.1.0.16\n" #define LOM_ON_RESP "Scheduled platform on\n" #define LOM_OFF_RESP "Scheduled platform off\n" #define LOM_CMD_INVAL "\ %s: not found\n" static void usage(void); static void prompt_loop(void); typedef enum { NONE, SSH, SER, SER_LOGIN } ilomtype_t; static ilomtype_t personality = NONE; static char *prog; #define OPTIONS "p:" static const struct option longopts[] = { { "personality", required_argument, 0, 'p' }, {0, 0, 0, 0}, }; int main(int argc, char *argv[]) { int c; prog = basename(argv[0]); while ((c = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) { switch (c) { case 'p': if (strcmp(optarg, "ssh") == 0) personality = SSH; else if (strcmp(optarg, "serial") == 0) personality = SER; else if (strcmp(optarg, "serial_loggedin") == 0) personality = SER_LOGIN; else usage(); break; default: usage(); } } if (optind < argc) usage(); if (personality == NONE) usage(); prompt_loop(); exit(0); } static void usage(void) { fprintf(stderr, "Usage: %s -p ssh|serial|serial_loggedin\n", prog); exit(1); } static void prompt_loop(void) { char buf[128]; static char plug[4]; int authenticated = 0; strcpy(plug, "Off"); switch (personality) { case SER: authenticated = 0; break; case SSH: authenticated = 1; break; case SER_LOGIN: authenticated = 2; break; case NONE: break; } for (;;) { switch (authenticated) { case 0: if (xreadline(LOM_LOGIN_PROMPT, buf, sizeof(buf)) == NULL) goto done; if (!strcmp(buf, "admin")) authenticated = 1; break; case 1: if (xreadline(LOM_PASSWD_PROMPT, buf, sizeof(buf)) == NULL) goto done; if (!strcmp(buf, "admin")) { authenticated = 2; printf(LOM_BANNER); } break; case 2: if (xreadline(LOM_PROMPT, buf, sizeof(buf)) == NULL) goto done; if (!strcmp(buf, "exit")) { goto done; } else if (!strcmp(buf, "platform get power state")) { printf("%s\n", plug); } else if (!strcmp(buf, "platform set power state -W -f -q on")) { if (!strcmp(plug, "Off")) { strcpy(plug, "On"); printf(LOM_ON_RESP); } } else if (!strcmp(buf, "platform set power state -W -f -q off")) { if (!strcmp(plug, "On")) { strcpy(plug, "Off"); printf(LOM_OFF_RESP); } } else { printf(LOM_CMD_INVAL, buf); } } continue; done: break; } } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/t/simulators/openbmc-httppower.c000066400000000000000000000073651467035776500216760ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* openbmc-httppower.c - mimic httppower talking to a openbmc server */ #include #include #include #include #include "xread.h" static void print_unauthenticated (void) { printf("{\n" "\"data\": {\n" "\"description\": \"Login required\"\n" "},\n" "\"message\": \"401 Unauthorized\",\n" "\"status\": \"error\"\n" "}\n"); } static void prompt_loop(void) { char buf[1024], urltmp[1024], datatmp[1024]; int hoststatus = 0; /* 0 = off, 1 = on */ int authenticated = 0; for (;;) { if (xreadline("httppower> ", buf, sizeof(buf)) == NULL) break; if (!strcmp(buf, "help")) { printf("Commands are:\n"); printf(" get url data\n"); printf(" post url data\n"); printf(" put url data\n"); } else if (sscanf(buf, "post login %s", datatmp) == 1) { if (!authenticated) authenticated = 1; printf("{\n" "\"data\": \"User 'root' logged in\",\n" "\"message\": \"200 OK\",\n" "\"status\": \"ok\"\n" "}\n"); } else if (sscanf(buf, "post logout %s", datatmp) == 1) { if (authenticated) { authenticated = 0; printf("{\n" "\"data\": \"User 'root' logged in\",\n" "\"message\": \"200 OK\",\n" "\"status\": \"ok\"\n" "}\n"); } else printf("{\n" "\"data\": \"No user logged in\",\n" "\"message\": \"200 OK\",\n" "\"status\": \"ok\"\n" "}\n"); } else if (sscanf(buf, "get %s", urltmp) == 1) { if (!authenticated) { print_unauthenticated (); continue; } if (strstr (urltmp, "CurrentPowerState") == NULL) goto err; printf("{\n" "\"data\": \"xyz.openbmc_project.State.Chassis.PowerState.%s\",\n" "\"message\": \"200 OK\",\n" "\"status\": \"ok\"\n" "}\n", hoststatus ? "On" : "Off"); } else if (sscanf(buf, "put xyz/openbmc_project/state/host0/attr/RequestedHostTransition %s", datatmp) == 1) { if (!authenticated) { print_unauthenticated (); continue; } if (strstr (datatmp, "On")) { hoststatus = 1; } else if (strstr (datatmp, "Off")) { hoststatus = 0; } else if (strstr (datatmp, "Reboot")) { if (!hoststatus) hoststatus = 1; } else goto err; /* Doesn't matter what operation, output success */ printf("{\n" "\"data\": null,\n" "\"message\": \"200 OK\",\n" "\"status\": \"ok\"\n" "}\n"); } else goto err; continue; err: printf("Error\n"); } } int main(int argc, char *argv[]) { prompt_loop(); exit (0); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/t/simulators/redfish-httppower.c000066400000000000000000000044341467035776500216710ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2021 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* redfish-httppower.c - mimic httppower talking to a redfish server */ #include #include #include #include #include "xread.h" static void prompt_loop(void) { char buf[1024], urltmp[1024], datatmp[1024]; int hoststatus = 0; /* 0 = off, 1 = on */ for (;;) { if (xreadline("httppower> ", buf, sizeof(buf)) == NULL) break; if (!strcmp(buf, "help")) { printf("Commands are:\n"); printf(" auth user:pass\n"); printf(" get url data\n"); printf(" post url data\n"); } else if (sscanf(buf, "auth %s", datatmp) == 1) { /* we're not authenticating for real, so do nothing */ } else if (sscanf(buf, "get %s", urltmp) == 1) { if (strstr (urltmp, "redfish") == NULL) goto err; printf("{\n" "\"PowerState\":\"%s\",\n" "}\n", hoststatus ? "On" : "Off"); } else if (sscanf(buf, "post redfish/v1/Systems/1/Actions/ComputerSystem.Reset %s", datatmp) == 1) { if (strstr (datatmp, "On")) { hoststatus = 1; } else if (strstr (datatmp, "ForceOff")) { hoststatus = 0; } else if (strstr (datatmp, "ForceRestart")) { if (!hoststatus) hoststatus = 1; } else goto err; /* Doesn't matter what operation, output success */ printf("{\n" "\"PowerState\":\"%s\",\n" "}\n", hoststatus ? "On" : "Off"); } else goto err; continue; err: printf("Error\n"); } } int main(int argc, char *argv[]) { prompt_loop(); exit (0); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/t/simulators/swpdu.c000066400000000000000000000063311467035776500173530ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2004 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ /* swpdu.c - appro swpdu simulator */ /* FIXME: created from swpdu.dev, thus needs a sync with reality */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include "xread.h" static void usage(void); static void _noop_handler(int signum); static void _prompt_loop(void); static char *prog; #define OPTIONS "p:" static const struct option longopts[] = { {0, 0, 0, 0}, }; int main(int argc, char *argv[]) { int c; prog = basename(argv[0]); while ((c = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) { switch (c) { default: usage(); } } if (optind < argc) usage(); if (signal(SIGPIPE, _noop_handler) == SIG_ERR) { perror("signal"); exit(1); } _prompt_loop(); exit(0); } static void usage(void) { fprintf(stderr, "Usage: %s -p v2|v3|v4\n", prog); exit(1); } static void _noop_handler(int signum) { fprintf(stderr, "%s: received signal %d\n", prog, signum); } static void _prompt_loop(void) { int i; char buf[128]; int num_plugs = 48; int plug[48]; int plug_origin = 1; for (i = 0; i < num_plugs; i++) { plug[i] = 0; } /* Process commands. */ while (1) { if (xreadline("", buf, sizeof(buf)) == NULL) break; if (strlen(buf) == 0) { /* */ } else if (!strcmp(buf, "exprange on")) { /* */ } else if (!strcmp(buf, "exprange off")) { /* */ } else if (!strcmp(buf, "status")) { for (i = 0; i < num_plugs; i++) printf ("port%d: %s\n", i + plug_origin, plug[i] ? "on" : "off"); } else if (sscanf(buf, "status %d", &i) == 1) { i -= plug_origin; if (i < 0 || i >= num_plugs) break; printf ("port%d: %s\n", i + plug_origin, plug[i] ? "on" : "off"); } else if (sscanf(buf, "on %d", &i) == 1) { i -= plug_origin; if (i < 0 || i >= num_plugs) break; plug[i] = 1; } else if (sscanf(buf, "off %d", &i) == 1) { i -= plug_origin; if (i < 0 || i >= num_plugs) break; plug[i] = 0; } else if (sscanf(buf, "cycle %d", &i) == 1) { i -= plug_origin; if (i < 0 || i >= num_plugs) break; plug[i] = 0; sleep(2); plug[i] = 1; } else break; printf("swpdu> "); } printf("Error, exiting"); exit (1); } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/t/simulators/vpcd.c000066400000000000000000000330241467035776500171440ustar00rootroot00000000000000/************************************************************\ * Copyright (C) 2001 The Regents of the University of California. * (c.f. DISCLAIMER, COPYING) * * This file is part of PowerMan, a remote power management program. * For details, see https://github.com/chaos/powerman. * * SPDX-License-Identifier: GPL-2.0-or-later \************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "xmalloc.h" #include "xread.h" #include "xpoll.h" #include "hostlist.h" static void usage(void); static void _noop_handler(int signum); static void _spew_one(int linenum); static void _spew(int lines); static void _prompt_loop(void); static void _setup_socket(char *port); #define NUM_PLUGS 16 static int plug[NUM_PLUGS]; static int beacon[NUM_PLUGS]; static int temp[NUM_PLUGS]; static int logged_in = 0; static int bad_plugs[NUM_PLUGS]; static int bad_plugs_count = 0; static char *prog; #define OPTIONS "p:b:" static const struct option longopts[] = { {"port", required_argument, 0, 'p'}, {"bad-plug", required_argument, 0, 'b'}, {0, 0, 0, 0}, }; int main(int argc, char *argv[]) { int i, c; char *port = NULL; prog = basename(argv[0]); while ((c = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) { switch (c) { case 'p': /* --port n */ port = xstrdup(optarg); break; case 'b': /* --bad-plug n */ bad_plugs[bad_plugs_count++] = atoi(optarg); break; default: usage(); } } if (optind < argc) usage(); if (signal(SIGPIPE, _noop_handler) == SIG_ERR) { perror("signal"); exit(1); } if (port) _setup_socket(port); for (i = 0; i < NUM_PLUGS; i++) { plug[i] = 0; beacon[i] = 0; temp[i] = 83 + i; } _prompt_loop(); exit(0); } static void usage(void) { fprintf(stderr, "Usage: %s\n", prog); exit(1); } static void _noop_handler(int signum) { fprintf(stderr, "%s: received signal %d\n", prog, signum); } /* Return with stdin/stdout reopened as a connected socket. */ #define LISTEN_BACKLOG 5 static void _setup_socket(char *serv) { struct addrinfo hints, *res, *r; int *fds, fd, fdlen, saved_errno, count, error, i, opt; char *what = NULL; xpollfd_t pfd; struct sockaddr_storage addr; socklen_t addr_size; short flags; /* get addresses to listen on for this port */ memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; if ((error = getaddrinfo(NULL, serv, &hints, &res))) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error)); exit(1); } if (res == NULL) { fprintf(stderr, "getaddrinfo: no address to bind to\n"); exit(1); } /* allocate array of listen fd's */ fdlen = 0; for (r = res; r != NULL; r = r->ai_next) fdlen++; fds = (int *)xmalloc(sizeof(int) * fdlen); /* bind fds to addresses and listen */ count = 0; saved_errno = 0; for (r = res, i = 0; r != NULL; r = r->ai_next, i++) { fds[i] = -1; if ((fd = socket(r->ai_family, r->ai_socktype, 0)) < 0) { saved_errno = errno; what = "socket"; continue; } opt = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { saved_errno = errno; what = "setsockopt"; close(fd); continue; } if (bind(fd, r->ai_addr, r->ai_addrlen) < 0) { saved_errno = errno; what = "bind"; close(fd); continue; } if (listen(fd, LISTEN_BACKLOG) < 0) { saved_errno = errno; what = "listen"; close(fd); continue; } fds[i] = fd; count++; } freeaddrinfo(res); if (count == 0) { fprintf(stderr, "%s: %s\n", what, strerror(saved_errno)); exit(1); } /* accept a connection on 'fd' */ pfd = xpollfd_create(); fd = -1; while (fd == -1) { xpollfd_zero(pfd); for (i = 0; i < fdlen; i++) { if (fds[i] != -1) xpollfd_set(pfd, fds[i], XPOLLIN); } if (xpoll(pfd, NULL) < 0) { fprintf(stderr, "poll: %s\n", strerror(errno)); exit(1); } for (i = 0; i < fdlen; i++) { if (fds[i] != -1) { flags = xpollfd_revents(pfd, fds[i]); if ((flags & (XPOLLERR|XPOLLHUP|XPOLLNVAL))) { fprintf(stderr, "poll: error on fd %d\n", fds[i]); exit(1); } if ((flags & XPOLLIN)) { addr_size = sizeof(addr); fd = accept(fds[i], (struct sockaddr *)&addr, &addr_size); if (fd < 0) { fprintf(stderr, "accept: %s\n", strerror(errno)); exit(1); } break; } } } } xpollfd_destroy(pfd); for (i = 0; i < fdlen; i++) { if (fds[i] != -1 && fds[i] != fd) close(fds[i]); } /* dup socket to stdio */ (void)close(0); if (dup2(fd, 0) < 0) { fprintf(stderr, "dup2(stdin): %s\n", strerror(errno)); exit(1); } (void)close(1); if (dup2(fd, 1) < 0) { fprintf(stderr, "dup2(stdout): %s\n", strerror(errno)); exit(1); } } #define SPEW \ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+[]" static void _spew_one(int linenum) { char buf[80]; linenum %= strlen(SPEW); memcpy(buf, SPEW + linenum, strlen(SPEW) - linenum); memcpy(buf + strlen(SPEW) - linenum, SPEW, linenum); buf[strlen(SPEW)] = '\0'; printf("%s\n", buf); } static void _spew(int lines) { int i; for (i = 0; i < lines; i++) _spew_one(i); } static int is_bad_plug(int n) { if (bad_plugs_count) { int i; for (i = 0; i < bad_plugs_count; i++) { if (bad_plugs[i] == n) return 1; } } return 0; } static void _prompt_loop(void) { int seq, i; char buf[128]; char prompt[128]; char range[128]; char *str; for (seq = 0;; seq++) { snprintf(prompt, sizeof(prompt), "%d vpc> ", seq); if (xreadline(prompt, buf, sizeof(buf)) == NULL) break; if (strlen(buf) == 0) continue; if (strcmp(buf, "logoff") == 0) { /* logoff */ printf("%d OK\n", seq); logged_in = 0; break; } if (strcmp(buf, "login") == 0) { /* logon */ logged_in = 1; goto ok; } if (!logged_in) { printf("%d Please login\n", seq); continue; } if (sscanf(buf, "stat %d", &i) == 1) { /* stat */ if (i < 0 || i >= NUM_PLUGS) { printf("%d BADVAL: %d\n", seq, i); continue; } str = !is_bad_plug(i) ? plug[i] ? "ON" : "OFF" : "ERROR"; printf("plug %d: %s\n", i, str); goto ok; } if (strcmp(buf, "stat *") == 0) { /* stat * */ for (i = 0; i < NUM_PLUGS; i++) { str = !is_bad_plug(i) ? plug[i] ? "ON" : "OFF" : "ERROR"; printf("plug %d: %s\n", i, str); } goto ok; } if (sscanf(buf, "beacon %d", &i) == 1) { /* beacon */ if (i < 0 || i >= NUM_PLUGS) { printf("%d BADVAL: %d\n", seq, i); continue; } str = !is_bad_plug(i) ? beacon[i] ? "ON" : "OFF" : "ERROR"; printf("plug %d: %s\n", i, str); goto ok; } if (strcmp(buf, "beacon *") == 0) { /* beacon * */ for (i = 0; i < NUM_PLUGS; i++) { str = !is_bad_plug(i) ? beacon[i] ? "ON" : "OFF" : "ERROR"; printf("plug %d: %s\n", i, str); } goto ok; } if (sscanf(buf, "temp %d", &i) == 1) { /* temp */ if (i < 0 || i >= NUM_PLUGS) { printf("%d BADVAL: %d\n", seq, i); continue; } if (!is_bad_plug(i)) printf("plug %d: %d\n", i, temp[i]); else printf("plug %d: ERROR\n", i); goto ok; } if (strcmp(buf, "temp *") == 0) { /* temp * */ for (i = 0; i < NUM_PLUGS; i++) { if (!is_bad_plug(i)) printf("plug %d: %d\n", i, temp[i]); else printf("plug %d: ERROR\n", i); } goto ok; } if (sscanf(buf, "spew %d", &i) == 1) { /* spew */ if (i <= 0) { printf("%d BADVAL: %d\n", seq, i); continue; } _spew(i); goto ok; } if (strcmp(buf, "on *") == 0) { /* on * */ for (i = 0; i < NUM_PLUGS; i++) { plug[i] = 1; printf("%d: %s\n", i, !is_bad_plug(i) ? "OK" : "ERROR"); } goto ok; } if (sscanf(buf, "on %d", &i) == 1) { /* on */ if (i < 0 || i >= NUM_PLUGS) { printf("%d BADVAL: %d\n", seq, i); continue; } plug[i] = 1; printf("%d: %s\n", i, !is_bad_plug(i) ? "OK" : "ERROR"); goto ok; } if (sscanf(buf, "on %s", range) == 1) { /* on */ hostlist_t hl = hostlist_create(range); if (!hl) { fprintf(stderr, "hostlist_create failed\n"); exit(1); } for (i = 0; i < hostlist_count(hl); i++) { char *p = hostlist_nth(hl, i); int plugnum = atoi(p); if (plugnum < 0 || plugnum >= NUM_PLUGS) printf("%d BADVAL: %d\n", seq, plugnum); else { plug[plugnum] = 1; str = !is_bad_plug(plugnum) ? "OK" : "ERROR"; printf("%d: %s\n", plugnum, str); } free(p); } hostlist_destroy(hl); goto ok; } if (strcmp(buf, "off *") == 0) { /* off * */ for (i = 0; i < NUM_PLUGS; i++) { plug[i] = 0; printf("%d: %s\n", i, !is_bad_plug(i) ? "OK" : "ERROR"); } goto ok; } if (sscanf(buf, "off %d", &i) == 1) { /* off */ if (i < 0 || i >= NUM_PLUGS) { printf("%d BADVAL: %d\n", seq, i); continue; } plug[i] = 0; printf("%d: %s\n", i, !is_bad_plug(i) ? "OK" : "ERROR"); goto ok; } if (sscanf(buf, "off %s", range) == 1) { /* off */ hostlist_t hl = hostlist_create(range); if (!hl) { fprintf(stderr, "hostlist_create failed\n"); exit(1); } for (i = 0; i < hostlist_count(hl); i++) { char *p = hostlist_nth(hl, i); int plugnum = atoi(p); if (plugnum < 0 || plugnum >= NUM_PLUGS) printf("%d BADVAL: %d\n", seq, plugnum); else { plug[plugnum] = 0; str = !is_bad_plug(plugnum) ? "OK" : "ERROR"; printf("%d: %s\n", plugnum, str); } free(p); } hostlist_destroy(hl); goto ok; } if (sscanf(buf, "flash %d", &i) == 1) { /* flash */ if (i < 0 || i >= NUM_PLUGS) { printf("%d BADVAL: %d\n", seq, i); continue; } if (is_bad_plug(i)) printf("%d: ERROR\n", i); else beacon[i] = 1; goto ok; } if (sscanf(buf, "unflash %d", &i) == 1) { /* unflash */ if (i < 0 || i >= NUM_PLUGS) { printf("%d BADVAL: %d\n", seq, i); continue; } if (is_bad_plug(i)) printf("%d: ERROR\n", i); else beacon[i] = 0; goto ok; } if (sscanf(buf, "reset %d", &i) == 1) { /* reset */ if (i < 0 || i >= NUM_PLUGS) { printf("%d BADVAL: %d\n", seq, i); continue; } sleep(1); /* noop */ goto ok; } if (sscanf(buf, "reset %s", range) == 1) { /* reset */ sleep(1); /* noop */ goto ok; } if (strcmp(buf, "reset *") == 0) { /* reset * */ sleep(1); /* noop */ goto ok; } printf("%d UNKNOWN: %s\n", seq, buf); continue; ok: printf("%d OK\n", seq); } } /* * vi:tabstop=4 shiftwidth=4 expandtab */ powerman-2.4.4/t/t0000-sharness.t000077500000000000000000000323341467035776500164240ustar00rootroot00000000000000#!/bin/sh # # Copyright (c) 2011-2013 Mathias Lafeldt # Copyright (c) 2005-2013 Git project # Copyright (c) 2005-2013 Junio C Hamano # # 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 http://www.gnu.org/licenses/ . test_description='Test Sharness itself' . `dirname $0`/sharness.sh ret="$?" test_expect_success 'sourcing sharness succeeds' ' test "$ret" = 0 ' test_expect_success 'success is reported like this' ' : ' test_expect_failure 'pretend we have a known breakage' ' false ' test_terminal () { perl "$SHARNESS_TEST_DIRECTORY"/test-terminal.perl "$@" } # If test_terminal works, then set a PERL_AND_TTY prereq for future tests: # (PERL and TTY prereqs may later be split if needed separately) test_terminal sh -c "test -t 1 && test -t 2" && test_set_prereq PERL_AND_TTY run_sub_test_lib_test () { name="$1" descr="$2" # stdin is the body of the test code prefix="$3" # optionally run sub-test under command opt="$4" # optionally call the script with extra option(s) mkdir "$name" && ( unset debug && unset verbose && cd "$name" && cat >".$name.t" <<-EOF && #!/bin/sh test_description='$descr (run in sub sharness) This is run in a sub sharness so that we do not get incorrect passing metrics ' # Point to the test/sharness.sh, which isn't in ../ as usual . "\$SHARNESS_TEST_SRCDIR"/sharness.sh EOF cat >>".$name.t" && chmod +x ".$name.t" && export SHARNESS_TEST_SRCDIR && $prefix ./".$name.t" $opt --chain-lint >out 2>err ) } check_sub_test_lib_test () { name="$1" # stdin is the expected output from the test ( unset verbose && unset debug && cd "$name" && ! test -s err && sed -e 's/^> //' -e 's/Z$//' >expect && test_cmp expect out ) } test_expect_success 'pretend we have a fully passing test suite' " run_sub_test_lib_test full-pass '3 passing tests' <<-\\EOF && for i in 1 2 3 do test_expect_success \"passing test #\$i\" 'true' done test_done EOF check_sub_test_lib_test full-pass <<-\\EOF > ok 1 - passing test #1 > ok 2 - passing test #2 > ok 3 - passing test #3 > # passed all 3 test(s) > 1..3 EOF " test_expect_success 'pretend we have a partially passing test suite' " test_must_fail run_sub_test_lib_test \ partial-pass '2/3 tests passing' <<-\\EOF && test_expect_success 'passing test #1' 'true' test_expect_success 'failing test #2' 'false' test_expect_success 'passing test #3' 'true' test_done EOF check_sub_test_lib_test partial-pass <<-\\EOF > ok 1 - passing test #1 > not ok 2 - failing test #2 # false > ok 3 - passing test #3 > # failed 1 among 3 test(s) > 1..3 EOF " test_expect_success 'pretend we have a known breakage' " run_sub_test_lib_test failing-todo 'A failing TODO test' <<-\\EOF && test_expect_success 'passing test' 'true' test_expect_failure 'pretend we have a known breakage' 'false' test_done EOF check_sub_test_lib_test failing-todo <<-\\EOF > ok 1 - passing test > not ok 2 - pretend we have a known breakage # TODO known breakage > # still have 1 known breakage(s) > # passed all remaining 1 test(s) > 1..2 EOF " test_expect_success 'pretend we have fixed a known breakage' " run_sub_test_lib_test passing-todo 'A passing TODO test' <<-\\EOF && test_expect_failure 'pretend we have fixed a known breakage' 'true' test_done EOF check_sub_test_lib_test passing-todo <<-\\EOF > ok 1 - pretend we have fixed a known breakage # TODO known breakage vanished > # 1 known breakage(s) vanished; please update test(s) > 1..1 EOF " test_expect_success 'pretend we have fixed one of two known breakages (run in sub sharness)' " run_sub_test_lib_test partially-passing-todos \ '2 TODO tests, one passing' <<-\\EOF && test_expect_failure 'pretend we have a known breakage' 'false' test_expect_success 'pretend we have a passing test' 'true' test_expect_failure 'pretend we have fixed another known breakage' 'true' test_done EOF check_sub_test_lib_test partially-passing-todos <<-\\EOF > not ok 1 - pretend we have a known breakage # TODO known breakage > ok 2 - pretend we have a passing test > ok 3 - pretend we have fixed another known breakage # TODO known breakage vanished > # 1 known breakage(s) vanished; please update test(s) > # still have 1 known breakage(s) > # passed all remaining 1 test(s) > 1..3 EOF " test_expect_success 'pretend we have a pass, fail, and known breakage' " test_must_fail run_sub_test_lib_test \ mixed-results1 'mixed results #1' <<-\\EOF && test_expect_success 'passing test' 'true' test_expect_success 'failing test' 'false' test_expect_failure 'pretend we have a known breakage' 'false' test_done EOF check_sub_test_lib_test mixed-results1 <<-\\EOF > ok 1 - passing test > not ok 2 - failing test > # false > not ok 3 - pretend we have a known breakage # TODO known breakage > # still have 1 known breakage(s) > # failed 1 among remaining 2 test(s) > 1..3 EOF " test_expect_success 'pretend we have a mix of all possible results' " test_must_fail run_sub_test_lib_test \ mixed-results2 'mixed results #2' <<-\\EOF && test_expect_success 'passing test' 'true' test_expect_success 'passing test' 'true' test_expect_success 'passing test' 'true' test_expect_success 'passing test' 'true' test_expect_success 'failing test' 'false' test_expect_success 'failing test' 'false' test_expect_success 'failing test' 'false' test_expect_failure 'pretend we have a known breakage' 'false' test_expect_failure 'pretend we have a known breakage' 'false' test_expect_failure 'pretend we have fixed a known breakage' 'true' test_done EOF check_sub_test_lib_test mixed-results2 <<-\\EOF > ok 1 - passing test > ok 2 - passing test > ok 3 - passing test > ok 4 - passing test > not ok 5 - failing test > # false > not ok 6 - failing test > # false > not ok 7 - failing test > # false > not ok 8 - pretend we have a known breakage # TODO known breakage > not ok 9 - pretend we have a known breakage # TODO known breakage > ok 10 - pretend we have fixed a known breakage # TODO known breakage vanished > # 1 known breakage(s) vanished; please update test(s) > # still have 2 known breakage(s) > # failed 3 among remaining 7 test(s) > 1..10 EOF " test_set_prereq HAVEIT haveit=no test_expect_success HAVEIT 'test runs if prerequisite is satisfied' ' test_have_prereq HAVEIT && haveit=yes ' donthaveit=yes test_expect_success DONTHAVEIT 'unmet prerequisite causes test to be skipped' ' donthaveit=no ' if test $haveit$donthaveit != yesyes then say "bug in test framework: prerequisite tags do not work reliably" exit 1 fi test_set_prereq HAVETHIS haveit=no test_expect_success HAVETHIS,HAVEIT 'test runs if prerequisites are satisfied' ' test_have_prereq HAVEIT && test_have_prereq HAVETHIS && haveit=yes ' donthaveit=yes test_expect_success HAVEIT,DONTHAVEIT 'unmet prerequisites causes test to be skipped' ' donthaveit=no ' donthaveiteither=yes test_expect_success DONTHAVEIT,HAVEIT 'unmet prerequisites causes test to be skipped' ' donthaveiteither=no ' if test $haveit$donthaveit$donthaveiteither != yesyesyes then say "bug in test framework: multiple prerequisite tags do not work reliably" exit 1 fi clean=no test_expect_success 'tests clean up after themselves' ' test_when_finished clean=yes ' if test $clean != yes then say "bug in test framework: basic cleanup command does not work reliably" exit 1 fi test_expect_success 'tests clean up even on failures' " test_must_fail run_sub_test_lib_test \ failing-cleanup 'Failing tests with cleanup commands' <<-\\EOF && test_expect_success 'tests clean up even after a failure' ' touch clean-after-failure && test_when_finished rm clean-after-failure && (exit 1) ' test_expect_success 'failure to clean up causes the test to fail' ' test_when_finished \"(exit 2)\" ' test_done EOF check_sub_test_lib_test failing-cleanup <<-\\EOF > not ok 1 - tests clean up even after a failure > # Z > # touch clean-after-failure && > # test_when_finished rm clean-after-failure && > # (exit 1) > # Z > not ok 2 - failure to clean up causes the test to fail > # Z > # test_when_finished \"(exit 2)\" > # Z > # failed 2 among 2 test(s) > 1..2 EOF " test_expect_success 'cleanup functions tun at the end of the test' " run_sub_test_lib_test cleanup-function 'Empty test with cleanup function' <<-\\EOF && cleanup 'echo cleanup-function-called >&5' test_done EOF check_sub_test_lib_test cleanup-function <<-\\EOF 1..0 cleanup-function-called EOF " test_expect_success 'We detect broken && chains' " test_must_fail run_sub_test_lib_test \ broken-chain 'Broken && chain' <<-\\EOF test_expect_success 'Cannot fail' ' true true ' test_done EOF " test_expect_success 'tests can be run from an alternate directory' ' # Act as if we have an installation of sharness in current dir: ln -sf $SHARNESS_TEST_SRCDIR/sharness.sh . && export working_path="$(pwd)" && cat >test.t <<-EOF && test_description="test run of script from alternate dir" . \$(dirname \$0)/sharness.sh test_expect_success "success" " true " test_expect_success "trash dir is subdir of working path" " test \"\$(cd .. && pwd)\" = \"\$working_path/test-rundir\" " test_done EOF ( # unset SHARNESS variables before sub-test unset SHARNESS_TEST_DIRECTORY SHARNESS_TEST_SRCDIR && # unset HARNESS_ACTIVE so we get a test-results dir unset HARNESS_ACTIVE && unset debug && unset verbose && chmod +x test.t && mkdir test-rundir && cd test-rundir && ../test.t >output 2>err && cat >expected <<-EOF && ok 1 - success ok 2 - trash dir is subdir of working path # passed all 2 test(s) 1..2 EOF test_cmp expected output && test -d test-results ) ' test_expect_success 'SHARNESS_ORIG_TERM propagated to sub-sharness' " ( export TERM=foo && unset SHARNESS_ORIG_TERM && run_sub_test_lib_test orig-term 'check original term' <<-\\EOF test_expect_success 'SHARNESS_ORIG_TERM is foo' ' test \"x\$SHARNESS_ORIG_TERM\" = \"xfoo\" ' test_done EOF ) " [ -z "$color" ] || test_set_prereq COLOR test_expect_success COLOR,PERL_AND_TTY 'sub-sharness still has color' " run_sub_test_lib_test \ test-color \ 'sub-sharness color check' \ test_terminal <<-\\EOF test_expect_success 'color is enabled' '[ -n \"\$color\" ]' test_done EOF " test_expect_success 'EXPENSIVE prereq not activated by default' " run_sub_test_lib_test no-long 'long test' <<-\\EOF && test_expect_success 'passing test' 'true' test_expect_success EXPENSIVE 'passing suposedly long test' 'true' test_done EOF check_sub_test_lib_test no-long <<-\\EOF > ok 1 - passing test > ok 2 # skip passing suposedly long test (missing EXPENSIVE) > # passed all 2 test(s) > 1..2 EOF " test_expect_success 'EXPENSIVE prereq is activated by --long' " run_sub_test_lib_test long 'long test' '' '--long' <<-\\EOF && test_expect_success 'passing test' 'true' test_expect_success EXPENSIVE 'passing suposedly long test' 'true' test_done EOF check_sub_test_lib_test long <<-\\EOF > ok 1 - passing test > ok 2 - passing suposedly long test > # passed all 2 test(s) > 1..2 EOF " test_expect_success 'loading sharness extensions works' ' # Act as if we have a new installation of sharness # under `extensions` directory. Then create # a sharness.d/ directory with a test extension function: mkdir extensions && ( unset verbose && unset debug && cd extensions && mkdir sharness.d && cat >sharness.d/test.sh <<-EOF && this_is_a_test() { return 0 } EOF ln -sf $SHARNESS_TEST_SRCDIR/sharness.sh . && cat >test-extension.t <<-\EOF && test_description="test sharness extensions" . ./sharness.sh test_expect_success "extension function is present" " this_is_a_test " test_done EOF unset SHARNESS_TEST_DIRECTORY SHARNESS_TEST_SRCDIR && chmod +x ./test-extension.t && ./test-extension.t >out 2>err && cat >expected <<-\EOF && ok 1 - extension function is present # passed all 1 test(s) 1..1 EOF test_cmp expected out ) ' test_expect_success 'empty sharness.d directory does not cause failure' ' # Act as if we have a new installation of sharness # under `extensions` directory. Then create # an empty sharness.d/ directory mkdir nil-extensions && ( unset debug && unset verbose && cd nil-extensions && mkdir sharness.d && ln -sf $SHARNESS_TEST_SRCDIR/sharness.sh . && cat >test.t <<-\EOF && test_description="sharness works" . ./sharness.sh test_expect_success "test success" " /bin/true " test_done EOF unset SHARNESS_TEST_DIRECTORY SHARNESS_TEST_SRCDIR && chmod +x ./test.t && ./test.t >out 2>err && cat >expected <<-\EOF && ok 1 - test success # passed all 1 test(s) 1..1 EOF test_cmp expected out ) ' test_expect_success INTERACTIVE 'Interactive tests work' ' echo -n "Please type yes and hit enter " && read -r var && test "$var" = "yes" ' test_done # vi: set ft=sh : powerman-2.4.4/t/t0001-powerman-client.t000077500000000000000000000020321467035776500176730ustar00rootroot00000000000000#!/bin/sh test_description='Test Powerman Client without server' . `dirname $0`/sharness.sh powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman test_expect_success 'powerman --help displays usage' ' $powerman --help >help.out && grep Usage: help.out ' test_expect_success 'powerman --badopt fails with error on stderr' ' test_must_fail $powerman --badopt 2>badopt.out && grep "Unknown option" badopt.out ' test_expect_success 'powerman without an action fails with message on stderr' ' test_must_fail $powerman -T 2>noaction.err && grep "No action was specified" noaction.err ' test_expect_success 'powerman with two actions fails with message on stderr' ' test_must_fail $powerman -1 -q t0 2>multiaction.err && grep "Only one action may be specified" multiaction.err ' test_expect_success 'powerman --version works' ' $powerman --version >version.out && test $(wc -l license.out && grep GPL license.out ' test_done # vi: set ft=sh powerman-2.4.4/t/t0002-pluglist.t000077500000000000000000000024721467035776500164430ustar00rootroot00000000000000#!/bin/sh test_description='Test pluglist class' . `dirname $0`/sharness.sh test_pluglist=$SHARNESS_BUILD_DIRECTORY/src/powerman/test_pluglist test_expect_success 'pluglist foo[1-500] p[1-500] maps expected host to p493' " $test_pluglist -f p493 'foo[1-500]' 'p[1-500]' >find.out && cat >find.exp <<-EOT plug=p493 node=foo493 EOT " test_expect_success 'pluglist t[1,2,3] p[999-1001] has expected map' " $test_pluglist 't[1,2,3]' 'p[999-1001]' >map1.out && cat >map1.exp <<-EOT && plug=p1001 node=t3 plug=p1000 node=t2 plug=p999 node=t1 EOT test_cmp map1.exp map1.out " test_expect_success 'pluglist foo[11-15] [1-5] correctly maps 1,2,3,4,5,6' " $test_pluglist -p1,2,3,4,5,6 'foo[11-15]' '[1-5]' >map2.out && cat >map2.exp <<-EOT && plug=1 node=foo11 plug=2 node=foo12 plug=3 node=foo13 plug=4 node=foo14 plug=5 node=foo15 plug=6 node=NULL EOT test_cmp map2.exp map2.out " test_expect_success 'pluglist foo[1-500] [1-500] correctly maps 1,2,3,4,5,6,7,8' " $test_pluglist -p 1,2,3,4,5,6,7,8 'foo[1-500]' '[1-500]' >map3.out \ 2>map3.err && cat >map3.exp <<-EOT && plug=1 node=foo1 plug=2 node=foo2 plug=3 node=foo3 plug=4 node=foo4 plug=5 node=foo5 plug=6 node=foo6 plug=7 node=foo7 plug=8 node=foo8 EOT test_cmp map3.exp map3.out && grep -q 'unknown plug' map3.err " test_done # vi: set ft=sh powerman-2.4.4/t/t0003-api-client.t000077500000000000000000000037471467035776500166340ustar00rootroot00000000000000#!/bin/sh test_description='Test simple Powerman API client' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman test_apiclient=$SHARNESS_BUILD_DIRECTORY/src/powerman/test_apiclient vpcd=$SHARNESS_BUILD_DIRECTORY/t/simulators/vpcd vpcdev=$SHARNESS_TEST_SRCDIR/etc/vpc.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11003 test_expect_success 'create test powerman.conf' ' cat >powerman.conf <<-EOT include "$vpcdev" listen "$testaddr" device "test0" "vpc" "$vpcd |&" node "t[0-15]" "test0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'API query works' ' $test_apiclient $testaddr q t1 >query.out && cat >query.exp <<-EOT && t1: off EOT test_cmp query.exp query.out ' test_expect_success 'API target list works' ' $test_apiclient $testaddr l >list.out && cat >list.exp <<-EOT && t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 t15 EOT test_cmp list.exp list.out ' test_expect_success 'API query shows t0 is off' ' $test_apiclient $testaddr q t0 >query2.out && cat >query2.exp <<-EOT && t0: off EOT test_cmp query2.exp query2.out ' test_expect_success 'API can turn on t0' ' $test_apiclient $testaddr 1 t0 ' test_expect_success 'API query shows t0 is on' ' $test_apiclient $testaddr q t0 >query3.out && cat >query3.exp <<-EOT && t0: on EOT test_cmp query3.exp query3.out ' test_expect_success 'API can turn off t0' ' $test_apiclient $testaddr 0 t0 ' test_expect_success 'API query shows t0 is off' ' $test_apiclient $testaddr q t0 >query4.out && cat >query4.exp <<-EOT && t0: off EOT test_cmp query4.exp query4.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0004-status-query.t000077500000000000000000000144331467035776500172700ustar00rootroot00000000000000#!/bin/sh test_description='Test Powerman status query' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman vpcd=$SHARNESS_BUILD_DIRECTORY/t/simulators/vpcd vpcdev=$SHARNESS_TEST_SRCDIR/etc/vpc.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11004 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create test powerman.conf' ' cat >powerman.conf <<-EOT include "$vpcdev" listen "$testaddr" device "test0" "vpc" "$vpcd |&" node "t[0-15]" "test0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'powerman -q works' ' $powerman -h $testaddr -q >query.out && makeoutput "" "t[0-15]" "" >query.exp && test_cmp query.exp query.out ' test_expect_success 'powerman -q t1 works' ' $powerman -h $testaddr -q t1 >query2.out && makeoutput "" "t1" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -q t1 t2 works' ' $powerman -h $testaddr -q t1 t2 >query2a.out && makeoutput "" "t[1-2]" "" >query2a.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -q t[3-5] works' ' $powerman -h $testaddr -q t[3-5] >query3.out && makeoutput "" "t[3-5]" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_expect_success 'create new powerman.conf with no status_all script' ' cat >powerman2.conf <<-EOT2 specification "vpc" { timeout 5.0 plug name { "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" } script login { send "login\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script logout { send "logoff\n" expect "[0-9]* OK\n" } script status { send "stat %s\n" expect "plug ([0-9]+): (ON|OFF)\n" setplugstate \$1 \$2 on="ON" off="OFF" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } } listen "$testaddr" device "test0" "vpc" "$vpcd |&" node "t[0-15]" "test0" EOT2 ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman2.conf & echo $! >powermand2.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'powerman -q works' ' $powerman -h $testaddr -q >nsa_query.out && makeoutput "" "t[0-15]" "" >nsa_query.exp && test_cmp nsa_query.exp nsa_query.out ' test_expect_success 'powerman -q t1 works' ' $powerman -h $testaddr -q t1 >nsa_query2.out && makeoutput "" "t1" "" >nsa_query2.exp && test_cmp nsa_query2.exp nsa_query2.out ' test_expect_success 'powerman -q t[3-5] works' ' $powerman -h $testaddr -q t[3-5] >nsa_query3.out && makeoutput "" "t[3-5]" "" >nsa_query3.exp && test_cmp nsa_query3.exp nsa_query3.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand2.pid) && wait ' test_expect_success 'create test powerman.conf with device over tcp' ' cat >powerman3.conf <<-EOT include "$vpcdev" listen "$testaddr" device "test0" "vpc" "127.0.0.1:10900" node "t[0-15]" "test0" EOT ' test_expect_success 'start device server' ' $vpcd -p 10900 & ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman3.conf & echo $! >powermand3.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q works' ' $powerman -h $testaddr -q >tcp_query.out && makeoutput "" "t[0-15]" "" >tcp_query.exp && test_cmp tcp_query.exp tcp_query.out ' test_expect_success 'powerman -q t1 works' ' $powerman -h $testaddr -q t1 >tcp_query2.out && makeoutput "" "t1" "" >tcp_query2.exp && test_cmp tcp_query2.exp tcp_query2.out ' test_expect_success 'powerman -q t[3-5] works' ' $powerman -h $testaddr -q t[3-5] >tcp_query3.out && makeoutput "" "t[3-5]" "" >tcp_query3.exp && test_cmp tcp_query3.exp tcp_query3.out ' # powermand will disconnect from device server, which will cause it to exit test_expect_success 'stop powerman daemon and device server' ' kill -15 $(cat powermand3.pid) && wait && wait ' test_expect_success 'create new powerman.conf with both status and status_all script' ' cat >powerman4.conf <<-EOT4 specification "vpc" { timeout 5.0 plug name { "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" } script login { send "login\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script logout { send "logoff\n" expect "[0-9]* OK\n" } script status { send "stat %s\n" expect "plug ([0-9]+): (ON|OFF)\n" setplugstate \$1 \$2 on="ON" off="OFF" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script status_all { send "stat *\n" foreachplug { expect "plug ([0-9]+): (ON|OFF)\n" setplugstate \$1 \$2 on="ON" off="OFF" } expect "[0-9]* OK\n" expect "[0-9]* vpc> " } } listen "$testaddr" device "test0" "vpc" "$vpcd |&" node "t[0-15]" "test0" EOT4 ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman4.conf & echo $! >powermand4.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'powerman -q works' ' $powerman -h $testaddr -q >all_query.out && makeoutput "" "t[0-15]" "" >all_query.exp && test_cmp all_query.exp all_query.out ' test_expect_success 'powerman -q uses status_all script on all plugs' ' $powerman -h $testaddr -T -q >all_queryT.out && count=`grep "stat" all_queryT.out | wc -l` && test $count = 1 ' test_expect_success 'powerman -q t[1-15] works' ' $powerman -h $testaddr -q t[1-15] >most_query.out && makeoutput "" "t[1-15]" "" >most_query.exp && test_cmp most_query.exp most_query.out ' test_expect_success 'powerman -q uses status script on not all plugs' ' $powerman -h $testaddr -T -q t[1-15] >most_queryT.out && count=`grep "stat" most_queryT.out | wc -l` && test $count = 15 ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand4.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0005-telemetry.t000077500000000000000000000115661467035776500166210ustar00rootroot00000000000000#!/bin/sh test_description='Test Powerman telemetry output' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman vpcd=$SHARNESS_BUILD_DIRECTORY/t/simulators/vpcd vpcdev=$SHARNESS_TEST_SRCDIR/etc/vpc.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11005 test_expect_success 'create test powerman.conf' ' cat >powerman.conf <<-EOT include "$vpcdev" listen "$testaddr" device "test0" "vpc" "$vpcd |&" node "t[0-15]" "test0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'powerman -q -T works' ' $powerman -h $testaddr -q -T >tel.out ' test_expect_success 'telemetry output contains send' ' grep -q "send(test0):" tel.out ' test_expect_success 'telemetry output contains recv' ' grep -q "recv(test0):" tel.out ' test_expect_success 'telemetry has expected size' ' test $(stat -c%s tel.out) -eq 576 ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' # Note: vpc server has a "spew" command that prints a long line. # We insert that in the status_all script to increase the volume # of telemetry data for testing. generate_config_spew() { local spew=$1 cat <<-EOT specification "vpc" { timeout 5.0 plug name { "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" } script login { send "login\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script logout { send "logoff\n" expect "[0-9]* OK\n" } script status_all { send "spew $spew\n" # noise generator expect "[0-9]* OK\n" expect "[0-9]* vpc> " send "stat *\n" foreachplug { expect "plug ([0-9]+): (ON|OFF)\n" setplugstate \$1 \$2 on="ON" off="OFF" } expect "[0-9]* OK\n" expect "[0-9]* vpc> " } } listen "$testaddr" device "test0" "vpc" "$vpcd |&" node "t[0-15]" "test0" EOT } test_expect_success 'create test powerman.conf with extra telemetry output < 1K' ' generate_config_spew 16 >powerman2.conf ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman2.conf & echo $! >powermand2.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'powerman -q -T works' ' $powerman -h $testaddr -q -T >tel2.out ' test_expect_success 'telemetry has expected size' ' test $(stat -c%s tel2.out) -eq 1926 ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand2.pid) && wait ' # spew more than 1K (MIN_DEV_BUF) but less than 64K (MAX_DEV_BUF) to # cause cbuf expansion but no wrap. (512 * 78 char = 39K) test_expect_success 'create test powerman.conf with 1K < telemetry output < 64K' ' generate_config_spew 512 >powerman3.conf ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman3.conf & echo $! >powermand3.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'powerman -q -T works' ' $powerman -h $testaddr -q -T >tel3.out ' test_expect_success 'telemetry has expected size' ' test $(stat -c%s tel3.out) -eq 41607 ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand3.pid) && wait ' # spew more than 64K (MAX_DEV_BUF) to cause cbuf wrap. # (1024 * 78 char = 78K) test_expect_success 'create test powerman.conf with telemetry output > 64K' ' generate_config_spew 1024 >powerman4.conf ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman4.conf & echo $! >powermand4.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'powerman -q -T works' ' $powerman -h $testaddr -q -T >tel4.out 2>tel4.err ' test_expect_success 'telemetry has expected size' ' test $(stat -c%s tel4.out) -eq 67002 ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand4.pid) && wait ' test_expect_success 'create test powerman.conf with telemetry output > 2*64K' ' # spew more than twice 64K (MAX_DEV_BUF) to cause double cbuf wrap. # (1900 * 78 char = 144K) generate_config_spew 1900 >powerman5.conf ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman5.conf & echo $! >powermand5.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'powerman -q -T works' ' $powerman -h $testaddr -q -T >tel5.out 2>tel5.err ' test_expect_success 'telemetry has expected size' ' test $(stat -c%s tel5.out) -eq 67002 ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand5.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0006-on-off-cycle.t000077500000000000000000000071561467035776500170710ustar00rootroot00000000000000#!/bin/sh test_description='Test Powerman power control options' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman vpcd=$SHARNESS_BUILD_DIRECTORY/t/simulators/vpcd vpcdev=$SHARNESS_TEST_SRCDIR/etc/vpc.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11006 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create test powerman.conf' ' cat >powerman.conf <<-EOT include "$vpcdev" listen "$testaddr" device "test0" "vpc" "$vpcd |&" node "t[0-15]" "test0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'powerman -q shows all nodes off' ' $powerman -h $testaddr -q >query1.out && makeoutput "" "t[0-15]" "" >query1.exp && test_cmp query1.exp query1.out ' test_expect_success 'powerman -1 t4 works, check singlet script called' ' $powerman -h $testaddr -T -1 t4 >on4.out && grep send on4.out | grep "on 4" && tail -n1 on4.out | grep "Command completed successfully" ' test_expect_success 'powerman -q shows t4 is on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t4" "t[0-3,5-15]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -0 t4 works, check singlet script called' ' $powerman -h $testaddr -T -0 t4 >off4.out && grep send off4.out | grep "off 4" && tail -n1 off4.out | grep "Command completed successfully" ' test_expect_success 'powerman -q shows all nodes off' ' $powerman -h $testaddr -q >query3.out && makeoutput "" "t[0-15]" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'powerman -c t5 works' ' $powerman -h $testaddr -c t5 >cycle5.out && echo "Command completed successfully" >cycle5.exp && test_cmp cycle5.exp cycle5.out ' test_expect_success 'powerman -q shows t5 on' ' $powerman -h $testaddr -q >query4.out && makeoutput "t5" "t[0-4,6-15]" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -1 t14 t15 works, check ranged script called' ' $powerman -h $testaddr -T -1 t14 t15 >on5.out && grep send on5.out | grep "on \[14\-15\]" && tail -n1 on5.out | grep "Command completed successfully" ' test_expect_success 'powerman -q shows t14 t15 on' ' $powerman -h $testaddr -q >query5.out && makeoutput "t[5,14-15]" "t[0-4,6-13]" "" >query5.exp && test_cmp query5.exp query5.out ' test_expect_success 'powerman -1 t[0-15] works, check all script called' ' $powerman -h $testaddr -T -1 t[0-15] >on6.out && grep send on6.out | grep "on \*" && tail -n1 on6.out | grep "Command completed successfully" ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query6.out && makeoutput "t[0-15]" "" "" >query6.exp && test_cmp query6.exp query6.out ' test_expect_success 'powerman -1 with no targets fails with useful error' ' test_must_fail $powerman -h $testaddr -1 2>notargets1.err && grep "Command requires targets" notargets1.err ' test_expect_success 'powerman -0 with no targets fails with useful error' ' test_must_fail $powerman -h $testaddr -0 2>notargets0.err && grep "Command requires targets" notargets0.err ' test_expect_success 'powerman -c with no targets fails with useful error' ' test_must_fail $powerman -h $testaddr -c 2>notargetsc.err && grep "Command requires targets" notargetsc.err ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0007-temperature.t000077500000000000000000000073321467035776500171420ustar00rootroot00000000000000#!/bin/sh test_description='Test Powerman temperature query' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman vpcd=$SHARNESS_BUILD_DIRECTORY/t/simulators/vpcd vpcdev=$SHARNESS_TEST_SRCDIR/etc/vpc.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11007 test_expect_success 'create test powerman.conf' ' cat >powerman.conf <<-EOT include "$vpcdev" listen "$testaddr" device "test0" "vpc" "$vpcd |&" node "t[0-15]" "test0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'powerman -t works' ' $powerman -h $testaddr -t >query_all.out && cat >query_all.exp <<-EOT && t0: 83 t1: 84 t2: 85 t3: 86 t4: 87 t5: 88 t6: 89 t7: 90 t8: 91 t9: 92 t10: 93 t11: 94 t12: 95 t13: 96 t14: 97 t15: 98 EOT test_cmp query_all.exp query_all.out ' test_expect_success 'powerman -t t13 works' ' $powerman -h $testaddr -t t13 >query_t13.out && echo "t13: 96" >query_t13.exp && test_cmp query_t13.exp query_t13.out ' test_expect_success 'powerman -t t[13-15] works' ' $powerman -h $testaddr -t t[13-15] >query_set.out && cat >query_set.exp <<-EOT && t13: 96 t14: 97 t15: 98 EOT test_cmp query_set.exp query_set.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_expect_success 'create new powerman.conf with both status_temp and status_temp_all script' ' cat >powerman2.conf <<-EOT2 specification "vpc" { timeout 5.0 plug name { "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" } script login { send "login\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script logout { send "logoff\n" expect "[0-9]* OK\n" } script status_temp { send "temp %s\n" expect "plug ([0-9]+): ([0-9]+)\n" setplugstate \$1 \$2 expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script status_temp_all { send "temp *\n" foreachplug { expect "plug ([0-9]+): ([0-9]+)\n" setplugstate \$1 \$2 } expect "[0-9]* OK\n" expect "[0-9]* vpc> " } } listen "$testaddr" device "test0" "vpc" "$vpcd |&" node "t[0-15]" "test0" EOT2 ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman2.conf & echo $! >powermand2.pid && $powerman --retry-connect=100 --server-host=$testaddr -t >/dev/null ' test_expect_success 'powerman -t works' ' $powerman -h $testaddr -t >all_query.out && cat >all_query.exp <<-EOT && t0: 83 t1: 84 t2: 85 t3: 86 t4: 87 t5: 88 t6: 89 t7: 90 t8: 91 t9: 92 t10: 93 t11: 94 t12: 95 t13: 96 t14: 97 t15: 98 EOT test_cmp all_query.exp all_query.out ' test_expect_success 'powerman -t uses temp_status_all script on all plugs' ' $powerman -h $testaddr -T -t >all_queryT.out && count=`grep "temp" all_queryT.out | wc -l` && test $count = 1 ' test_expect_success 'powerman -t t[1-15] works' ' $powerman -h $testaddr -t t[1-15] >most_query.out && cat >most_query.exp <<-EOT && t1: 84 t2: 85 t3: 86 t4: 87 t5: 88 t6: 89 t7: 90 t8: 91 t9: 92 t10: 93 t11: 94 t12: 95 t13: 96 t14: 97 t15: 98 EOT test_cmp most_query.exp most_query.out ' test_expect_success 'powerman -t uses temp_status script on not all plugs' ' $powerman -h $testaddr -T -t t[1-15] >most_queryT.out && count=`grep "temp" most_queryT.out | wc -l` && test $count = 15 ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand2.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0008-beacon.t000077500000000000000000000111401467035776500160250ustar00rootroot00000000000000#!/bin/sh test_description='Test Powerman beacon options' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman vpcd=$SHARNESS_BUILD_DIRECTORY/t/simulators/vpcd vpcdev=$SHARNESS_TEST_SRCDIR/etc/vpc.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11008 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create test powerman.conf' ' cat >powerman.conf <<-EOT include "$vpcdev" listen "$testaddr" device "test0" "vpc" "$vpcd |&" node "t[0-15]" "test0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'powerman -b shows all beacons off' ' $powerman -h $testaddr -b >query1.out && makeoutput "" "t[0-15]" "" >query1.exp && test_cmp query1.exp query1.out ' test_expect_success 'powerman -f t[13-15] works' ' $powerman -h $testaddr -f t[13-15] >flash.out && echo "Command completed successfully" >flash.exp && test_cmp flash.exp flash.out ' test_expect_success 'powerman -b shows beacons t[13-15] on' ' $powerman -h $testaddr -b >query2.out && makeoutput "t[13-15]" "t[0-12]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -u t13 works' ' $powerman -h $testaddr -u t13 >unflash.out && echo "Command completed successfully" >unflash.exp && test_cmp unflash.exp unflash.out ' test_expect_success 'powerman -b shows beacons t[14-15] on' ' $powerman -h $testaddr -b >query3.out && makeoutput "t[14-15]" "t[0-13]" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'powerman -b t13 shows beacon t13 off' ' $powerman -h $testaddr -b t13 >query4.out && makeoutput "" "t13" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -b t14 shows beacon t14 on' ' $powerman -h $testaddr -b t14 >query5.out && makeoutput "t14" "" "" >query5.exp && test_cmp query5.exp query5.out ' test_expect_success 'powerman -f with no targets fails with useful error' ' test_must_fail $powerman -h $testaddr -f 2>notargetsf.err && grep "Command requires targets" notargetsf.err ' test_expect_success 'powerman -u with no targets fails with useful error' ' test_must_fail $powerman -h $testaddr -u 2>notargetsu.err && grep "Command requires targets" notargetsu.err ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_expect_success 'create new powerman.conf with both status_beacon and status_beacon_all script' ' cat >powerman2.conf <<-EOT2 specification "vpc" { timeout 5.0 plug name { "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" } script login { send "login\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script logout { send "logoff\n" expect "[0-9]* OK\n" } script status_beacon { send "beacon %s\n" expect "plug ([0-9]+): (ON|OFF)\n" setplugstate \$1 \$2 on="ON" off="OFF" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script status_beacon_all { send "beacon *\n" foreachplug { expect "plug ([0-9]+): (ON|OFF)\n" setplugstate \$1 \$2 on="ON" off="OFF" } expect "[0-9]* OK\n" expect "[0-9]* vpc> " } } listen "$testaddr" device "test0" "vpc" "$vpcd |&" node "t[0-15]" "test0" EOT2 ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman2.conf & echo $! >powermand2.pid && $powerman --retry-connect=100 --server-host=$testaddr -b >/dev/null ' test_expect_success 'powerman -b works' ' $powerman -h $testaddr -b >all_query.out && makeoutput "" "t[0-15]" "" >all_query.exp && test_cmp all_query.exp all_query.out ' test_expect_success 'powerman -b uses beacon_status_all script on all plugs' ' $powerman -h $testaddr -T -b >all_queryT.out && count=`grep "beacon" all_queryT.out | wc -l` && test $count = 1 ' test_expect_success 'powerman -b t[1-15] works' ' $powerman -h $testaddr -b t[1-15] >most_query.out && makeoutput "" "t[1-15]" "" >most_query.exp && test_cmp most_query.exp most_query.out ' test_expect_success 'powerman -b uses beacon_status script on not all plugs' ' $powerman -h $testaddr -T -b t[1-15] >most_queryT.out && count=`grep "beacon" most_queryT.out | wc -l` && test $count = 15 ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand2.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0009-reset.t000077500000000000000000000026721467035776500157330ustar00rootroot00000000000000#!/bin/sh test_description='Test Powerman reset control' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman vpcd=$SHARNESS_BUILD_DIRECTORY/t/simulators/vpcd vpcdev=$SHARNESS_TEST_SRCDIR/etc/vpc.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11009 test_expect_success 'create test powerman.conf' ' cat >powerman.conf <<-EOT include "$vpcdev" listen "$testaddr" device "test0" "vpc" "$vpcd |&" node "t[0-15]" "test0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'powerman -r t1 works' ' $powerman -h $testaddr -r t1 >reset1.out && echo "Command completed successfully" >reset1.exp && test_cmp reset1.exp reset1.out ' test_expect_success 'powerman -r t[3-5] works' ' $powerman -h $testaddr -r t[3-5] >reset2.out && echo "Command completed successfully" >reset2.exp && test_cmp reset2.exp reset2.out ' test_expect_success 'powerman -r with no targets fails with useful error' ' test_must_fail $powerman -h $testaddr -r 2>notargets.err && grep "Command requires targets" notargets.err ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0010-device-status.t000077500000000000000000000054151467035776500173570ustar00rootroot00000000000000#!/bin/sh test_description='Test Device status command' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman vpcd=$SHARNESS_BUILD_DIRECTORY/t/simulators/vpcd vpcdev=$SHARNESS_TEST_SRCDIR/etc/vpc.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11010 test_expect_success 'create test powerman.conf' ' cat >powerman.conf <<-EOT include "$vpcdev" listen "$testaddr" device "test0" "vpc" "$vpcd |&" device "test1" "vpc" "$vpcd |&" node "t[0-3]" "test0" node "t[4-7]" "test1" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'powerman -d works' ' $powerman -h $testaddr -d >device.out && cat >device.exp <<-EOT && test0: state=connected reconnects=000 actions=002 type=vpc hosts=t[0-3] test1: state=connected reconnects=000 actions=002 type=vpc hosts=t[4-7] EOT test_cmp device.exp device.out ' test_expect_success 'run powerman -q t1' ' $powerman -h $testaddr -q t1 >/dev/null ' test_expect_success 'powerman -d shows additional action' ' $powerman -h $testaddr -d >device2.out && cat >device2.exp <<-EOT && test0: state=connected reconnects=000 actions=003 type=vpc hosts=t[0-3] test1: state=connected reconnects=000 actions=002 type=vpc hosts=t[4-7] EOT test_cmp device2.exp device2.out ' test_expect_success 'running powerman -d t1 returns stats for test0' ' $powerman -h $testaddr -d t1 >device3.out && cat >device3.exp <<-EOT && test0: state=connected reconnects=000 actions=003 type=vpc hosts=t[0-3] EOT test_cmp device3.exp device3.out ' test_expect_success 'running powerman -d t[1,5] returns stats for both' ' $powerman -h $testaddr -d t[1,5] >device4.out && cat >device4.exp <<-EOT && test0: state=connected reconnects=000 actions=003 type=vpc hosts=t[0-3] test1: state=connected reconnects=000 actions=002 type=vpc hosts=t[4-7] EOT test_cmp device4.exp device4.out ' # FWIW the device query computes the intersection between plugs and devices # and the empty set is treated as a valid result, so this is not an error. # That seems a bit wrong but since this is mainly a test option, maybe not # worth changing. test_expect_success 'running powerman -d xyz returns nothing' ' $powerman -h $testaddr -d xyz >device5.out && test_must_fail test -s device5.out ' # Should this be somewhere else? test_expect_success 'powerman -l lists targets' ' $powerman -h $testaddr -l >list.out && echo "t[0-7]" >list.exp && test_cmp list.exp list.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0011-device-timeout.t000077500000000000000000000055071467035776500175250ustar00rootroot00000000000000#!/bin/sh test_description='Test Device timeouts' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman vpcd=$SHARNESS_BUILD_DIRECTORY/t/simulators/vpcd vpcdev=$SHARNESS_TEST_SRCDIR/etc/vpc.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11011 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create test powerman.conf with broken status_all' ' cat >powerman.conf <<-EOT specification "vpcbroke" { timeout 2.0 plug name { "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" } script login { send "login\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script logout { send "logoff\n" expect "[0-9]* OK\n" } # Hacked not to work script status_all { send "stat *\n" expect "WONTGETTHIS" } } listen "$testaddr" device "test0" "vpcbroke" "$vpcd |&" node "t[0-15]" "test0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q fails due to timeout' ' test_must_fail $powerman -h $testaddr -q >query.out ' test_expect_success 'and command had expected output' ' echo test0: action timed out waiting for expected response >query.exp && makeoutput "" "" "t[0-15]" >>query.exp && echo Query completed with errors >>query.exp && test_cmp query.exp query.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_expect_success 'add another device (16 more plugs) but this one works' ' cat >>powerman.conf <<-EOT include "$vpcdev" device "test1" "vpc" "$vpcd |&" node "t[16-31]" "test1" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q t[14-18] times out' ' test_must_fail $powerman -h $testaddr -q t[14-18] >query2.out ' test_expect_success 'and command partially succeeded' ' echo test0: action timed out waiting for expected response \ >query2.exp && makeoutput "" "t[16-18]" "t[14-15]" >>query2.exp && echo Query completed with errors >>query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -q t[16-31] works' ' $powerman -h $testaddr -q t[16-31] >query3.out && makeoutput "" "t[16-31]" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0012-device-delay.t000077500000000000000000000047231467035776500171350ustar00rootroot00000000000000#!/bin/sh test_description='Ensure that delays are processed expeditiously' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman vpcd=$SHARNESS_BUILD_DIRECTORY/t/simulators/vpcd vpcdev=$SHARNESS_TEST_SRCDIR/etc/vpc.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11012 test_expect_success 'create test powerman.conf with cycle of only delay' ' cat >powerman.conf <<-EOT specification "vpcfakecycle" { timeout 2 plug name { "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" } script login { send "login\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script cycle { delay 0.01 } } listen "$testaddr" device "test0" "vpcfakecycle" "$vpcd |&" node "t[0-15]" "test0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'run powerman -c t1 128x in a row' ' for i in $(seq 0 127); do \ $powerman -h $testaddr -c t1; \ done >cycle.out && for i in $(seq 0 127); do \ echo Command completed successfully done >cycle.exp && test_cmp cycle.exp cycle.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_expect_success 'create test powerman.conf with cycle of delay + io' ' cat >powerman2.conf <<-EOT specification "vpcfakecycle2" { timeout 2 plug name { "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" } script login { send "login\n" expect "[0-9]* OK\n" expect "[0-9]* vpc> " } script cycle { delay 0.01 send "\n" expect "[0-9]* vpc> " } } listen "$testaddr" device "test0" "vpcfakecycle2" "$vpcd |&" node "t[0-15]" "test0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman2.conf & echo $! >powermand2.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'run powerman -c t1 128x in a row' ' for i in $(seq 0 127); do \ $powerman -h $testaddr -c t1; \ done >cycle2.out && test_cmp cycle.exp cycle2.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand2.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0013-baytech-rpc3-nc.t000077500000000000000000000163651467035776500174720ustar00rootroot00000000000000#!/bin/sh test_description='Check Baytech RPC-3 NC device script' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman baytech=$SHARNESS_BUILD_DIRECTORY/t/simulators/baytech rpc3dev=$SHARNESS_TEST_SRCDIR/../etc/devices/baytech-rpc3-nc.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11013 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create powerman.conf with two rpc3 devices (16 plugs)' ' cat >powerman.conf <<-EOT listen "$testaddr" include "$rpc3dev" device "b0" "baytech-rpc3-nc" "$baytech -p rpc3-nc |&" device "b1" "baytech-rpc3-nc" "$baytech -p rpc3-de |&" node "t[0-7]" "b0" node "t[8-15]" "b1" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query.out && makeoutput "" "t[0-15]" "" >query.exp && test_cmp query.exp query.out ' test_expect_success 'powerman -1 t0,t8 works' ' $powerman -h $testaddr -1 t0,t8 >on.out && echo Command completed successfully >on.exp && test_cmp on.exp on.out ' test_expect_success 'powerman -q shows t0,t8 on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t[0,8]" "t[1-7,9-15]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -c t0,t8 works' ' $powerman -h $testaddr -c t0,t8 >cycle.out && echo Command completed successfully >cycle.exp && test_cmp cycle.exp cycle.out ' test_expect_success 'powerman -q shows t0,t8 on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t[0,8]" "t[1-7,9-15]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -0 t0,t8 works' ' $powerman -h $testaddr -0 t0,t8 >off.out && echo Command completed successfully >off.exp && test_cmp off.exp off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query3.out && makeoutput "" "t[0-15]" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'powerman -1 t[0-15] works' ' $powerman -h $testaddr -1 t[0-15] >on2.out && echo Command completed successfully >on2.exp && test_cmp on2.exp on2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query4.out && makeoutput "t[0-15]" "" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -c t[0-15] works' ' $powerman -h $testaddr -c t[0-15] >cycle2.out && echo Command completed successfully >cycle2.exp && test_cmp cycle2.exp cycle2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query4.out && makeoutput "t[0-15]" "" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -0 t[0-15] works' ' $powerman -h $testaddr -0 t[0-15] >off2.out && echo Command completed successfully >off2.exp && test_cmp off2.exp off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query5.out && makeoutput "" "t[0-15]" "" >query5.exp && test_cmp query5.exp query5.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_expect_success 'create powerman.conf with 16 rpc3 devices (128 plugs)' ' cat >powerman2.conf <<-EOT listen "$testaddr" include "$rpc3dev" device "b0" "baytech-rpc3-nc" "$baytech -p rpc3-nc |&" device "b1" "baytech-rpc3-nc" "$baytech -p rpc3-nc |&" device "b2" "baytech-rpc3-nc" "$baytech -p rpc3-nc |&" device "b3" "baytech-rpc3-nc" "$baytech -p rpc3-nc |&" device "b4" "baytech-rpc3-nc" "$baytech -p rpc3-nc |&" device "b5" "baytech-rpc3-nc" "$baytech -p rpc3-nc |&" device "b6" "baytech-rpc3-nc" "$baytech -p rpc3-nc |&" device "b7" "baytech-rpc3-nc" "$baytech -p rpc3-nc |&" device "b8" "baytech-rpc3-nc" "$baytech -p rpc3-de |&" device "b9" "baytech-rpc3-nc" "$baytech -p rpc3-de |&" device "b10" "baytech-rpc3-nc" "$baytech -p rpc3-de |&" device "b11" "baytech-rpc3-nc" "$baytech -p rpc3-de |&" device "b12" "baytech-rpc3-nc" "$baytech -p rpc3-de |&" device "b13" "baytech-rpc3-nc" "$baytech -p rpc3-de |&" device "b14" "baytech-rpc3-nc" "$baytech -p rpc3-de |&" device "b15" "baytech-rpc3-nc" "$baytech -p rpc3-de |&" node "t[0-7]" "b0" node "t[8-15]" "b1" node "t[16-23]" "b2" node "t[24-31]" "b3" node "t[32-39]" "b4" node "t[40-47]" "b5" node "t[48-55]" "b6" node "t[56-63]" "b7" node "t[64-71]" "b8" node "t[72-79]" "b9" node "t[80-87]" "b10" node "t[88-95]" "b11" node "t[96-103]" "b12" node "t[104-111]" "b13" node "t[112-119]" "b14" node "t[120-127]" "b15" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman2.conf & echo $! >powermand2.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >big_query.out && makeoutput "" "t[0-127]" "" >big_query.exp && test_cmp big_query.exp big_query.out ' SET1="t[0,8,16,24,32,40,48,56,64,72,80,88,96,104,112,120]" SET2="t[1-7,9-15,17-23,25-31,33-39,41-47,49-55,57-63,65-71,73-79,81-87,89-95,97-103,105-111,113-119,121-127]" test_expect_success 'powerman -1 first plug in each device works' ' $powerman -h $testaddr -1 $SET1 >big_on.out && echo Command completed successfully >big_on.exp && test_cmp big_on.exp big_on.out ' test_expect_success 'powerman -q shows expected output' ' $powerman -h $testaddr -q >big_query2.out && makeoutput "$SET1" "$SET2" "" >big_query2.exp test_cmp big_query2.exp big_query2.out ' test_expect_success 'powerman -c first plug in each device works' ' $powerman -h $testaddr -c $SET1 >big_cycle.out && echo Command completed successfully >big_cycle.exp && test_cmp big_cycle.exp big_cycle.out ' test_expect_success 'powerman -q shows expected output' ' $powerman -h $testaddr -q >big_query3.out && makeoutput "$SET1" "$SET2" "" >big_query3.exp test_cmp big_query3.exp big_query3.out ' test_expect_success 'powerman -0 first plug in each device works' ' $powerman -h $testaddr -0 $SET1 >big_off.out && echo Command completed successfully >big_off.exp && test_cmp big_off.exp big_off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >big_query4.out && makeoutput "" "t[0-127]" "" >big_query4.exp && test_cmp big_query4.exp big_query4.out ' test_expect_success 'powerman -1 t[0-127] works' ' $powerman -h $testaddr -1 t[0-127] >big_on2.out && echo Command completed successfully >big_on2.exp && test_cmp big_on2.exp big_on2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >big_query5.out && makeoutput "t[0-127]" "" "" >big_query5.exp && test_cmp big_query5.exp big_query5.out ' test_expect_success 'powerman -0 t[0-127] works' ' $powerman -h $testaddr -0 t[0-127] >big_off2.out && echo Command completed successfully >big_off2.exp && test_cmp big_off2.exp big_off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >big_query6.out && makeoutput "" "t[0-127]" "" >big_query6.exp && test_cmp big_query6.exp big_query6.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand2.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0014-baytech-rpc28-nc.t000077500000000000000000000150051467035776500175500ustar00rootroot00000000000000#!/bin/sh test_description='Check Baytech RPC-28 NC device script' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman baytech=$SHARNESS_BUILD_DIRECTORY/t/simulators/baytech rpc28dev=$SHARNESS_TEST_SRCDIR/../etc/devices/baytech-rpc28-nc.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11014 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create powerman config with one device (20 plugs)' ' cat >powerman.conf <<-EOT listen "$testaddr" include "$rpc28dev" device "b0" "baytech-rpc28-nc" "$baytech -p rpc28-nc |&" node "t[0-19]" "b0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query.out && makeoutput "" "t[0-19]" "" >query.exp && test_cmp query.exp query.out ' test_expect_success 'powerman -1 t0 works' ' $powerman -h $testaddr -1 t0 >on.out && echo Command completed successfully >on.exp && test_cmp on.exp on.out ' test_expect_success 'powerman -q shows t0 on' ' $powerman -h $testaddr -q >query1.out && makeoutput "t0" "t[1-19]" "" >query1.exp && test_cmp query1.exp query1.out ' test_expect_success 'powerman -c t0 works' ' $powerman -h $testaddr -c t0 >cycle.out && echo Command completed successfully >cycle.exp && test_cmp cycle.exp cycle.out ' test_expect_success 'powerman -q shows t0 on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t0" "t[1-19]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -0 t0 works' ' $powerman -h $testaddr -0 t0 >off.out && echo Command completed successfully >off.exp && test_cmp off.exp off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query3.out && makeoutput "" "t[0-19]" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'powerman -1 t[0-19] works' ' $powerman -h $testaddr -1 t[0-19] >on2.out && echo Command completed successfully >on2.exp && test_cmp on2.exp on2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query4.out && makeoutput "t[0-19]" "" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -c t[0-19] works' ' $powerman -h $testaddr -c t[0-19] >cycle2.out && echo Command completed successfully >cycle2.exp && test_cmp cycle2.exp cycle2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query4.out && makeoutput "t[0-19]" "" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -0 t[0-19] works' ' $powerman -h $testaddr -0 t[0-19] >off2.out && echo Command completed successfully >off2.exp && test_cmp off2.exp off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query5.out && makeoutput "" "t[0-19]" "" >query5.exp && test_cmp query5.exp query5.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_expect_success 'create powerman config with 8 devices (160 plugs)' ' cat >powerman2.conf <<-EOT listen "$testaddr" include "$rpc28dev" device "b0" "baytech-rpc28-nc" "$baytech -p rpc28-nc |&" device "b1" "baytech-rpc28-nc" "$baytech -p rpc28-nc |&" device "b2" "baytech-rpc28-nc" "$baytech -p rpc28-nc |&" device "b3" "baytech-rpc28-nc" "$baytech -p rpc28-nc |&" device "b4" "baytech-rpc28-nc" "$baytech -p rpc28-nc |&" device "b5" "baytech-rpc28-nc" "$baytech -p rpc28-nc |&" device "b6" "baytech-rpc28-nc" "$baytech -p rpc28-nc |&" device "b7" "baytech-rpc28-nc" "$baytech -p rpc28-nc |&" node "t[0-19]" "b0" node "t[20-39]" "b1" node "t[40-59]" "b2" node "t[60-79]" "b3" node "t[80-99]" "b4" node "t[100-119]" "b5" node "t[120-139]" "b6" node "t[140-159]" "b7" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman2.conf & echo $! >powermand2.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >big_query.out && makeoutput "" "t[0-159]" "" >big_query.exp && test_cmp big_query.exp big_query.out ' SET1_RPC28="t[0,20,40,60,80,100,120,140]" SET2_RPC28="t[1-19,21-39,41-59,61-79,81-99,101-119,121-139,141-159]" test_expect_success 'powerman -1 first plug in each device works' ' $powerman -h $testaddr -1 $SET1_RPC28 >big_on.out && echo Command completed successfully >big_on.exp && test_cmp big_on.exp big_on.out ' test_expect_success 'powerman -q shows expected output' ' $powerman -h $testaddr -q >big_query2.out && makeoutput "$SET1_RPC28" "$SET2_RPC28" "" >big_query2.exp test_cmp big_query2.exp big_query2.out ' test_expect_success 'powerman -c first plug in each device works' ' $powerman -h $testaddr -c $SET1_RPC28 >big_cycle.out && echo Command completed successfully >big_cycle.exp && test_cmp big_cycle.exp big_cycle.out ' test_expect_success 'powerman -q shows expected output' ' $powerman -h $testaddr -q >big_query3.out && makeoutput "$SET1_RPC28" "$SET2_RPC28" "" >big_query3.exp test_cmp big_query3.exp big_query3.out ' test_expect_success 'powerman -0 first plug in each device works' ' $powerman -h $testaddr -0 $SET1_RPC28 >big_off.out && echo Command completed successfully >big_off.exp && test_cmp big_off.exp big_off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >big_query4.out && makeoutput "" "t[0-159]" "" >big_query4.exp && test_cmp big_query4.exp big_query4.out ' test_expect_success 'powerman -1 t[0-159] works' ' $powerman -h $testaddr -1 t[0-159] >big_on2.out && echo Command completed successfully >big_on2.exp && test_cmp big_on2.exp big_on2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >big_query5.out && makeoutput "t[0-159]" "" "" >big_query5.exp && test_cmp big_query5.exp big_query5.out ' test_expect_success 'powerman -0 t[0-159] works' ' $powerman -h $testaddr -0 t[0-159] >big_off2.out && echo Command completed successfully >big_off2.exp && test_cmp big_off2.exp big_off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >big_query6.out && makeoutput "" "t[0-159]" "" >big_query6.exp && test_cmp big_query6.exp big_query6.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand2.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0015-baytech-rpc3.t000077500000000000000000000156641467035776500170770ustar00rootroot00000000000000#!/bin/sh test_description='Check Baytech RPC-3 (not NC) device script' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman baytech=$SHARNESS_BUILD_DIRECTORY/t/simulators/baytech rpc3dev=$SHARNESS_TEST_SRCDIR/../etc/devices/baytech.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11015 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create powerman.conf with one rpc3 device (8 plugs)' ' cat >powerman.conf <<-EOT listen "$testaddr" include "$rpc3dev" device "b0" "baytech" "$baytech -p rpc3 |&" node "t[0-7]" "b0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query.out && makeoutput "" "t[0-7]" "" >query.exp && test_cmp query.exp query.out ' test_expect_success 'powerman -1 t0 works' ' $powerman -h $testaddr -1 t0 >on.out && echo Command completed successfully >on.exp && test_cmp on.exp on.out ' test_expect_success 'powerman -q shows t0 on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t0" "t[1-7]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -c t0 works' ' $powerman -h $testaddr -c t0 >cycle.out && echo Command completed successfully >cycle.exp && test_cmp cycle.exp cycle.out ' test_expect_success 'powerman -q shows t0 on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t0" "t[1-7]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -0 t0 works' ' $powerman -h $testaddr -0 t0 >off.out && echo Command completed successfully >off.exp && test_cmp off.exp off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query3.out && makeoutput "" "t[0-7]" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'powerman -1 t[0-7] works' ' $powerman -h $testaddr -1 t[0-7] >on2.out && echo Command completed successfully >on2.exp && test_cmp on2.exp on2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query4.out && makeoutput "t[0-7]" "" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -c t[0-7] works' ' $powerman -h $testaddr -c t[0-7] >cycle2.out && echo Command completed successfully >cycle2.exp && test_cmp cycle2.exp cycle2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query4.out && makeoutput "t[0-7]" "" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -0 t[0-7] works' ' $powerman -h $testaddr -0 t[0-7] >off2.out && echo Command completed successfully >off2.exp && test_cmp off2.exp off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query5.out && makeoutput "" "t[0-7]" "" >query5.exp && test_cmp query5.exp query5.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_expect_success 'create powerman.conf with 16 rpc3 devices (128 plugs)' ' cat >powerman2.conf <<-EOT listen "$testaddr" include "$rpc3dev" device "b0" "baytech" "$baytech -p rpc3 |&" device "b1" "baytech" "$baytech -p rpc3 |&" device "b2" "baytech" "$baytech -p rpc3 |&" device "b3" "baytech" "$baytech -p rpc3 |&" device "b4" "baytech" "$baytech -p rpc3 |&" device "b5" "baytech" "$baytech -p rpc3 |&" device "b6" "baytech" "$baytech -p rpc3 |&" device "b7" "baytech" "$baytech -p rpc3 |&" device "b8" "baytech" "$baytech -p rpc3 |&" device "b9" "baytech" "$baytech -p rpc3 |&" device "b10" "baytech" "$baytech -p rpc3 |&" device "b11" "baytech" "$baytech -p rpc3 |&" device "b12" "baytech" "$baytech -p rpc3 |&" device "b13" "baytech" "$baytech -p rpc3 |&" device "b14" "baytech" "$baytech -p rpc3 |&" device "b15" "baytech" "$baytech -p rpc3 |&" node "t[0-7]" "b0" node "t[8-15]" "b1" node "t[16-23]" "b2" node "t[24-31]" "b3" node "t[32-39]" "b4" node "t[40-47]" "b5" node "t[48-55]" "b6" node "t[56-63]" "b7" node "t[64-71]" "b8" node "t[72-79]" "b9" node "t[80-87]" "b10" node "t[88-95]" "b11" node "t[96-103]" "b12" node "t[104-111]" "b13" node "t[112-119]" "b14" node "t[120-127]" "b15" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman2.conf & echo $! >powermand2.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >big_query.out && makeoutput "" "t[0-127]" "" >big_query.exp && test_cmp big_query.exp big_query.out ' SET1="t[0,8,16,24,32,40,48,56,64,72,80,88,96,104,112,120]" SET2="t[1-7,9-15,17-23,25-31,33-39,41-47,49-55,57-63,65-71,73-79,81-87,89-95,97-103,105-111,113-119,121-127]" test_expect_success 'powerman -1 first plug in each device works' ' $powerman -h $testaddr -1 $SET1 >big_on.out && echo Command completed successfully >big_on.exp && test_cmp big_on.exp big_on.out ' test_expect_success 'powerman -q shows expected output' ' $powerman -h $testaddr -q >big_query2.out && makeoutput "$SET1" "$SET2" "" >big_query2.exp test_cmp big_query2.exp big_query2.out ' test_expect_success 'powerman -c first plug in each device works' ' $powerman -h $testaddr -c $SET1 >big_cycle.out && echo Command completed successfully >big_cycle.exp && test_cmp big_cycle.exp big_cycle.out ' test_expect_success 'powerman -q shows expected output' ' $powerman -h $testaddr -q >big_query3.out && makeoutput "$SET1" "$SET2" "" >big_query3.exp test_cmp big_query3.exp big_query3.out ' test_expect_success 'powerman -0 first plug in each device works' ' $powerman -h $testaddr -0 $SET1 >big_off.out && echo Command completed successfully >big_off.exp && test_cmp big_off.exp big_off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >big_query4.out && makeoutput "" "t[0-127]" "" >big_query4.exp && test_cmp big_query4.exp big_query4.out ' test_expect_success 'powerman -1 t[0-127] works' ' $powerman -h $testaddr -1 t[0-127] >big_on2.out && echo Command completed successfully >big_on2.exp && test_cmp big_on2.exp big_on2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >big_query5.out && makeoutput "t[0-127]" "" "" >big_query5.exp && test_cmp big_query5.exp big_query5.out ' test_expect_success 'powerman -0 t[0-127] works' ' $powerman -h $testaddr -0 t[0-127] >big_off2.out && echo Command completed successfully >big_off2.exp && test_cmp big_off2.exp big_off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >big_query6.out && makeoutput "" "t[0-127]" "" >big_query6.exp && test_cmp big_query6.exp big_query6.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand2.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0016-icebox-v3.t000077500000000000000000000225531467035776500164060ustar00rootroot00000000000000#!/bin/sh test_description='Check Linux Networx icebox v3 device script' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman icebox=$SHARNESS_BUILD_DIRECTORY/t/simulators/icebox iceboxdev=$SHARNESS_TEST_SRCDIR/../etc/devices/icebox3.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11016 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create powerman.conf with one icebox device (10 plugs)' ' cat >powerman.conf <<-EOT listen "$testaddr" include "$iceboxdev" device "i0" "icebox3" "$icebox -p v3 |&" node "t[0-9]" "i0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query.out && makeoutput "" "t[0-9]" "" >query.exp && test_cmp query.exp query.out ' test_expect_success 'powerman -1 t0 works' ' $powerman -h $testaddr -1 t0 >on.out && echo Command completed successfully >on.exp && test_cmp on.exp on.out ' test_expect_success 'powerman -q shows t0 on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t0" "t[1-9]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -c t0 works' ' $powerman -h $testaddr -c t0 >cycle.out && echo Command completed successfully >cycle.exp && test_cmp cycle.exp cycle.out ' test_expect_success 'powerman -q shows t0 on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t0" "t[1-9]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -0 t0 works' ' $powerman -h $testaddr -0 t0 >off.out && echo Command completed successfully >off.exp && test_cmp off.exp off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query3.out && makeoutput "" "t[0-9]" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'powerman -1 t[0-9] works' ' $powerman -h $testaddr -1 t[0-9] >on2.out && echo Command completed successfully >on2.exp && test_cmp on2.exp on2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query4.out && makeoutput "t[0-9]" "" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -c t[0-9] works' ' $powerman -h $testaddr -c t[0-9] >cycle2.out && echo Command completed successfully >cycle2.exp && test_cmp cycle2.exp cycle2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query4.out && makeoutput "t[0-9]" "" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -0 t[0-9] works' ' $powerman -h $testaddr -0 t[0-9] >off2.out && echo Command completed successfully >off2.exp && test_cmp off2.exp off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query5.out && makeoutput "" "t[0-9]" "" >query5.exp && test_cmp query5.exp query5.out ' test_expect_success 'powerman -b shows all beacons off' ' $powerman -h $testaddr -b >beacon.out && makeoutput "" "t[0-9]" "" >beacon.exp && test_cmp beacon.exp beacon.out ' test_expect_success 'powerman -f t0 works' ' $powerman -h $testaddr -f t0 >flash.out && echo Command completed successfully >flash.exp && test_cmp flash.exp flash.out ' test_expect_success 'powerman -b shows beacon t0 on' ' $powerman -h $testaddr -b >beacon2.out && makeoutput "t0" "t[1-9]" "" >beacon2.exp && test_cmp beacon2.exp beacon2.out ' test_expect_success 'powerman -u t0 works' ' $powerman -h $testaddr -u t0 >unflash.out && echo Command completed successfully >unflash.exp && test_cmp unflash.exp unflash.out ' test_expect_success 'powerman -b shows all beacons off' ' $powerman -h $testaddr -b >beacon3.out && makeoutput "" "t[0-9]" "" >beacon3.exp && test_cmp beacon3.exp beacon3.out ' test_expect_success 'powerman -t works' ' $powerman -h $testaddr -t >temp.out && cat >temp.exp <<-EOT && t0: 73: t1: 74: t2: 75: t3: 76: t4: 77: t5: 78: t6: 79: t7: 80: t8: 81: t9: 82: EOT test_cmp temp.exp temp.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' # N.B. icebox3.dev covers v3 and v4 firmware which are slightly different. # For this second test, emulate v4 firmware. test_expect_success 'create powerman.conf with 16 icebox3 (v4 mode) devices (160 plugs)' ' cat >powerman2.conf <<-EOT listen "$testaddr" include "$iceboxdev" device "i0" "icebox3" "$icebox -p v4 |&" device "i1" "icebox3" "$icebox -p v4 |&" device "i2" "icebox3" "$icebox -p v4 |&" device "i3" "icebox3" "$icebox -p v4 |&" device "i4" "icebox3" "$icebox -p v4 |&" device "i5" "icebox3" "$icebox -p v4 |&" device "i6" "icebox3" "$icebox -p v4 |&" device "i7" "icebox3" "$icebox -p v4 |&" device "i8" "icebox3" "$icebox -p v4 |&" device "i9" "icebox3" "$icebox -p v4 |&" device "i10" "icebox3" "$icebox -p v4 |&" device "i11" "icebox3" "$icebox -p v4 |&" device "i12" "icebox3" "$icebox -p v4 |&" device "i13" "icebox3" "$icebox -p v4 |&" device "i14" "icebox3" "$icebox -p v4 |&" device "i15" "icebox3" "$icebox -p v4 |&" node "t[0-9]" "i0" node "t[10-19]" "i1" node "t[20-29]" "i2" node "t[30-39]" "i3" node "t[40-49]" "i4" node "t[50-59]" "i5" node "t[60-69]" "i6" node "t[70-79]" "i7" node "t[80-89]" "i8" node "t[90-99]" "i9" node "t[100-109]" "i10" node "t[110-119]" "i11" node "t[120-129]" "i12" node "t[130-139]" "i13" node "t[140-149]" "i14" node "t[150-159]" "i15" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman2.conf & echo $! >powermand2.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >big_query.out && makeoutput "" "t[0-159]" "" >big_query.exp && test_cmp big_query.exp big_query.out ' SET1="t[0,10,20,30,40,50,60,70,80,90,100,110,120,130,140,150]" SET2="t[1-9,11-19,21-29,31-39,41-49,51-59,61-69,71-79,81-89,91-99,101-109,111-119,121-129,131-139,141-149,151-159]" test_expect_success 'powerman -1 first plug in each device works' ' $powerman -h $testaddr -1 $SET1 >big_on.out && echo Command completed successfully >big_on.exp && test_cmp big_on.exp big_on.out ' test_expect_success 'powerman -q shows expected output' ' $powerman -h $testaddr -q >big_query2.out && makeoutput "$SET1" "$SET2" "" >big_query2.exp test_cmp big_query2.exp big_query2.out ' test_expect_success 'powerman -c first plug in each device works' ' $powerman -h $testaddr -c $SET1 >big_cycle.out && echo Command completed successfully >big_cycle.exp && test_cmp big_cycle.exp big_cycle.out ' test_expect_success 'powerman -q shows expected output' ' $powerman -h $testaddr -q >big_query3.out && makeoutput "$SET1" "$SET2" "" >big_query3.exp test_cmp big_query3.exp big_query3.out ' test_expect_success 'powerman -0 first plug in each device works' ' $powerman -h $testaddr -0 $SET1 >big_off.out && echo Command completed successfully >big_off.exp && test_cmp big_off.exp big_off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >big_query4.out && makeoutput "" "t[0-159]" "" >big_query4.exp && test_cmp big_query4.exp big_query4.out ' test_expect_success 'powerman -1 t[0-159] works' ' $powerman -h $testaddr -1 t[0-159] >big_on2.out && echo Command completed successfully >big_on2.exp && test_cmp big_on2.exp big_on2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >big_query5.out && makeoutput "t[0-159]" "" "" >big_query5.exp && test_cmp big_query5.exp big_query5.out ' test_expect_success 'powerman -0 t[0-159] works' ' $powerman -h $testaddr -0 t[0-159] >big_off2.out && echo Command completed successfully >big_off2.exp && test_cmp big_off2.exp big_off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >big_query6.out && makeoutput "" "t[0-159]" "" >big_query6.exp && test_cmp big_query6.exp big_query6.out ' test_expect_success 'powerman -b shows all beacons off' ' $powerman -h $testaddr -b >big_beacon.out && makeoutput "" "t[0-159]" "" >big_beacon.exp && test_cmp big_beacon.exp big_beacon.out ' test_expect_success 'powerman -f first plug in each device works' ' $powerman -h $testaddr -f $SET1 >big_flash.out && echo Command completed successfully >big_flash.exp && test_cmp big_flash.exp big_flash.out ' test_expect_success 'powerman -b shows expected output' ' $powerman -h $testaddr -b >big_beacon2.out && makeoutput "$SET1" "$SET2" "" >big_beacon2.exp && test_cmp big_beacon2.exp big_beacon2.out ' test_expect_success 'powerman -u first plug in each device works' ' $powerman -h $testaddr -u $SET1 >big_unflash.out && echo Command completed successfully >big_unflash.exp && test_cmp big_unflash.exp big_unflash.out ' test_expect_success 'powerman -b shows all beacons off' ' $powerman -h $testaddr -b >beacon3.out && makeoutput "" "t[0-159]" "" >beacon3.exp && test_cmp beacon3.exp beacon3.out ' test_expect_success 'powerman -t works' ' $powerman -h $testaddr -t >big_temp.out && for i in $(seq 0 15); do \ for j in $(seq 0 9); do echo "t$(($i*10+$j)): $((73+$j)):"; done; \ done >big_temp.exp && test_cmp big_temp.exp big_temp.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand2.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0017-icebox-v2.t000077500000000000000000000166641467035776500164140ustar00rootroot00000000000000#!/bin/sh test_description='Check Linux Networx icebox v2 device script' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman icebox=$SHARNESS_BUILD_DIRECTORY/t/simulators/icebox iceboxdev=$SHARNESS_TEST_SRCDIR/../etc/devices/icebox.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11017 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create powerman.conf with one icebox device (10 plugs)' ' cat >powerman.conf <<-EOT listen "$testaddr" include "$iceboxdev" device "i0" "icebox" "$icebox -p v2 |&" node "t[0-9]" "i0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query.out && makeoutput "" "t[0-9]" "" >query.exp && test_cmp query.exp query.out ' test_expect_success 'powerman -1 t0 works' ' $powerman -h $testaddr -1 t0 >on.out && echo Command completed successfully >on.exp && test_cmp on.exp on.out ' test_expect_success 'powerman -q shows t0 on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t0" "t[1-9]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -c t0 works' ' $powerman -h $testaddr -c t0 >cycle.out && echo Command completed successfully >cycle.exp && test_cmp cycle.exp cycle.out ' test_expect_success 'powerman -q shows t0 on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t0" "t[1-9]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -0 t0 works' ' $powerman -h $testaddr -0 t0 >off.out && echo Command completed successfully >off.exp && test_cmp off.exp off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query3.out && makeoutput "" "t[0-9]" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'powerman -1 t[0-9] works' ' $powerman -h $testaddr -1 t[0-9] >on2.out && echo Command completed successfully >on2.exp && test_cmp on2.exp on2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query4.out && makeoutput "t[0-9]" "" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -c t[0-9] works' ' $powerman -h $testaddr -c t[0-9] >cycle2.out && echo Command completed successfully >cycle2.exp && test_cmp cycle2.exp cycle2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query4.out && makeoutput "t[0-9]" "" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -0 t[0-9] works' ' $powerman -h $testaddr -0 t[0-9] >off2.out && echo Command completed successfully >off2.exp && test_cmp off2.exp off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query5.out && makeoutput "" "t[0-9]" "" >query5.exp && test_cmp query5.exp query5.out ' test_expect_success 'powerman -t works' ' $powerman -h $testaddr -t >temp.out && cat >temp.exp <<-EOT && t0: 73,0,0,0 t1: 74,0,0,0 t2: 75,0,0,0 t3: 76,0,0,0 t4: 77,0,0,0 t5: 78,0,0,0 t6: 79,0,0,0 t7: 80,0,0,0 t8: 81,0,0,0 t9: 82,0,0,0 EOT test_cmp temp.exp temp.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_expect_success 'create powerman.conf with 16 icebox devices (160 plugs)' ' cat >powerman2.conf <<-EOT listen "$testaddr" include "$iceboxdev" device "i0" "icebox" "$icebox -p v2 |&" device "i1" "icebox" "$icebox -p v2 |&" device "i2" "icebox" "$icebox -p v2 |&" device "i3" "icebox" "$icebox -p v2 |&" device "i4" "icebox" "$icebox -p v2 |&" device "i5" "icebox" "$icebox -p v2 |&" device "i6" "icebox" "$icebox -p v2 |&" device "i7" "icebox" "$icebox -p v2 |&" device "i8" "icebox" "$icebox -p v2 |&" device "i9" "icebox" "$icebox -p v2 |&" device "i10" "icebox" "$icebox -p v2 |&" device "i11" "icebox" "$icebox -p v2 |&" device "i12" "icebox" "$icebox -p v2 |&" device "i13" "icebox" "$icebox -p v2 |&" device "i14" "icebox" "$icebox -p v2 |&" device "i15" "icebox" "$icebox -p v2 |&" node "t[0-9]" "i0" node "t[10-19]" "i1" node "t[20-29]" "i2" node "t[30-39]" "i3" node "t[40-49]" "i4" node "t[50-59]" "i5" node "t[60-69]" "i6" node "t[70-79]" "i7" node "t[80-89]" "i8" node "t[90-99]" "i9" node "t[100-109]" "i10" node "t[110-119]" "i11" node "t[120-129]" "i12" node "t[130-139]" "i13" node "t[140-149]" "i14" node "t[150-159]" "i15" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman2.conf & echo $! >powermand2.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >big_query.out && makeoutput "" "t[0-159]" "" >big_query.exp && test_cmp big_query.exp big_query.out ' SET1="t[0,10,20,30,40,50,60,70,80,90,100,110,120,130,140,150]" SET2="t[1-9,11-19,21-29,31-39,41-49,51-59,61-69,71-79,81-89,91-99,101-109,111-119,121-129,131-139,141-149,151-159]" test_expect_success 'powerman -1 first plug in each device works' ' $powerman -h $testaddr -1 $SET1 >big_on.out && echo Command completed successfully >big_on.exp && test_cmp big_on.exp big_on.out ' test_expect_success 'powerman -q shows expected output' ' $powerman -h $testaddr -q >big_query2.out && makeoutput "$SET1" "$SET2" "" >big_query2.exp test_cmp big_query2.exp big_query2.out ' test_expect_success 'powerman -c first plug in each device works' ' $powerman -h $testaddr -c $SET1 >big_cycle.out && echo Command completed successfully >big_cycle.exp && test_cmp big_cycle.exp big_cycle.out ' test_expect_success 'powerman -q shows expected output' ' $powerman -h $testaddr -q >big_query3.out && makeoutput "$SET1" "$SET2" "" >big_query3.exp test_cmp big_query3.exp big_query3.out ' test_expect_success 'powerman -0 first plug in each device works' ' $powerman -h $testaddr -0 $SET1 >big_off.out && echo Command completed successfully >big_off.exp && test_cmp big_off.exp big_off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >big_query4.out && makeoutput "" "t[0-159]" "" >big_query4.exp && test_cmp big_query4.exp big_query4.out ' test_expect_success 'powerman -1 t[0-159] works' ' $powerman -h $testaddr -1 t[0-159] >big_on2.out && echo Command completed successfully >big_on2.exp && test_cmp big_on2.exp big_on2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >big_query5.out && makeoutput "t[0-159]" "" "" >big_query5.exp && test_cmp big_query5.exp big_query5.out ' test_expect_success 'powerman -0 t[0-159] works' ' $powerman -h $testaddr -0 t[0-159] >big_off2.out && echo Command completed successfully >big_off2.exp && test_cmp big_off2.exp big_off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >big_query6.out && makeoutput "" "t[0-159]" "" >big_query6.exp && test_cmp big_query6.exp big_query6.out ' test_expect_success 'powerman -t works' ' $powerman -h $testaddr -t >big_temp.out && for i in $(seq 0 15); do \ for j in $(seq 0 9); \ do echo "t$(($i*10+$j)): $((73+$j)),0,0,0"; \ done; \ done >big_temp.exp && test_cmp big_temp.exp big_temp.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand2.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0018-cyclades-pm.t000077500000000000000000000074301467035776500170070ustar00rootroot00000000000000#!/bin/sh test_description='Check Cyclades PM8, PM10, PM20, PM42 scripts' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman cyclades=$SHARNESS_BUILD_DIRECTORY/t/simulators/cyclades pm8dev=$SHARNESS_TEST_SRCDIR/../etc/devices/cyclades-pm8.dev pm10dev=$SHARNESS_TEST_SRCDIR/../etc/devices/cyclades-pm10.dev pm20dev=$SHARNESS_TEST_SRCDIR/../etc/devices/cyclades-pm20.dev pm42dev=$SHARNESS_TEST_SRCDIR/../etc/devices/cyclades-pm42.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11018 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create powerman.conf with pm8,pm10,pm20,pm42 devices (80 plugs)' ' cat >powerman.conf <<-EOT listen "$testaddr" include "$pm8dev" include "$pm10dev" include "$pm20dev" include "$pm42dev" device "d0" "pm8" "$cyclades -p pm8 |&" device "d1" "pm10" "$cyclades -p pm10 |&" device "d2" "pm20" "$cyclades -p pm20 |&" device "d3" "pm42" "$cyclades -p pm42 |&" node "t[0-7]" "d0" node "t[8-17]" "d1" node "t[18-37]" "d2" node "t[38-79]" "d3" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query.out && makeoutput "" "t[0-79]" "" >query.exp && test_cmp query.exp query.out ' test_expect_success 'powerman -1 t[0,8,18,38] works' ' $powerman -h $testaddr -1 t[0,8,18,38] >on.out && echo Command completed successfully >on.exp && test_cmp on.exp on.out ' test_expect_success 'powerman -q shows those nodes on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t[0,8,18,38]" "t[1-7,9-17,19-37,39-79]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -c t[0,8,18,38] works' ' $powerman -h $testaddr -c t[0,8,18,38] >cycle.out && echo Command completed successfully >cycle.exp && test_cmp cycle.exp cycle.out ' test_expect_success 'powerman -q shows those nodes on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t[0,8,18,38]" "t[1-7,9-17,19-37,39-79]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -0 t[0,8,18,38] works' ' $powerman -h $testaddr -0 t[0,8,18,38] >off.out && echo Command completed successfully >off.exp && test_cmp off.exp off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query3.out && makeoutput "" "t[0-79]" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'powerman -1 t[0-79] works' ' $powerman -h $testaddr -1 t[0-79] >on2.out && echo Command completed successfully >on2.exp && test_cmp on2.exp on2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query4.out && makeoutput "t[0-79]" "" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -c t[0-79] works' ' $powerman -h $testaddr -c t[0-79] >cycle2.out && echo Command completed successfully >cycle2.exp && test_cmp cycle2.exp cycle2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query4.out && makeoutput "t[0-79]" "" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -0 t[0-79] works' ' $powerman -h $testaddr -0 t[0-79] >off2.out && echo Command completed successfully >off2.exp && test_cmp off2.exp off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query5.out && makeoutput "" "t[0-79]" "" >query5.exp && test_cmp query5.exp query5.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0019-insteon-plm.t000077500000000000000000000066021467035776500170540ustar00rootroot00000000000000#!/bin/sh test_description='Check Insteon PLM scripts with plmpower' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman plmpower=$SHARNESS_BUILD_DIRECTORY/src/plmpower/plmpower plmdev=$SHARNESS_TEST_SRCDIR/../etc/devices/plmpower.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11019 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } # Reminder: X10 devices have no ability to report power status so # their state is always "unknown". test_expect_success 'create powerman.conf with plmpower (t0 Insteon, t1 X10)' ' cat >powerman.conf <<-EOT listen "$testaddr" include "$plmdev" device "d0" "plmpower" "$plmpower -T |&" node "t0" "d0" "aa.bb.cc" node "t1" "d0" "G1" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows t0 off, t1 unknown' ' $powerman -h $testaddr -q >query.out && makeoutput "" "t0" "t1" >query.exp && test_cmp query.exp query.out ' test_expect_success 'powerman -1 t0 works' ' $powerman -h $testaddr -1 t0 >on.out && echo Command completed successfully >on.exp && test_cmp on.exp on.out ' test_expect_success 'powerman -q shows t0 on, t1 unknown' ' $powerman -h $testaddr -q >query2.out && makeoutput "t0" "" "t1" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -c t0 works' ' $powerman -h $testaddr -c t0 >cycle.out && echo Command completed successfully >cycle.exp && test_cmp cycle.exp cycle.out ' test_expect_success 'powerman -q shows t0 on, t1 unknown' ' $powerman -h $testaddr -q >query2.out && makeoutput "t0" "" "t1" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -0 t0 works' ' $powerman -h $testaddr -0 t0 >off.out && echo Command completed successfully >off.exp && test_cmp off.exp off.out ' test_expect_success 'powerman -q shows t0 off, t1 unknown off' ' $powerman -h $testaddr -q >query3.out && makeoutput "" "t0" "t1" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'powerman -1 t[0-1] works' ' $powerman -h $testaddr -1 t[0-1] >on2.out && echo Command completed successfully >on2.exp && test_cmp on2.exp on2.out ' test_expect_success 'powerman -q shows t0 on, t1 uknonwn' ' $powerman -h $testaddr -q >query4.out && makeoutput "t0" "" "t1" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -c t[0-1] works' ' $powerman -h $testaddr -c t[0-1] >cycle2.out && echo Command completed successfully >cycle2.exp && test_cmp cycle2.exp cycle2.out ' test_expect_success 'powerman -q shows t0 on, t1 unknown' ' $powerman -h $testaddr -q >query4.out && makeoutput "t0" "" "t1" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -0 t[0-1] works' ' $powerman -h $testaddr -0 t[0-1] >off2.out && echo Command completed successfully >off2.exp && test_cmp off2.exp off2.out ' test_expect_success 'powerman -q shows t0 off, t1 unknown' ' $powerman -h $testaddr -q >query5.out && makeoutput "" "t0" "t1" >query5.exp && test_cmp query5.exp query5.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0020-digital-loggers-lpc.t000077500000000000000000000062311467035776500204260ustar00rootroot00000000000000#!/bin/sh test_description='Check Digital Loggers Inc LPC device' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman dli=$SHARNESS_BUILD_DIRECTORY/t/simulators/dli dlidev=$SHARNESS_TEST_SRCDIR/../etc/devices/dli.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11020 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create powerman.conf for DLI LPC device (8 plugs)' ' cat >powerman.conf <<-EOT listen "$testaddr" include "$dlidev" device "d0" "dli" "$dli |&" node "t[0-7]" "d0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query.out && makeoutput "" "t[0-7]" "" >query.exp && test_cmp query.exp query.out ' test_expect_success 'powerman -1 t0 works' ' $powerman -h $testaddr -1 t0 >on.out && echo Command completed successfully >on.exp && test_cmp on.exp on.out ' test_expect_success 'powerman -q shows t0 on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t0" "t[1-7]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -c t0 works' ' $powerman -h $testaddr -c t0 >cycle.out && echo Command completed successfully >cycle.exp && test_cmp cycle.exp cycle.out ' test_expect_success 'powerman -q shows t0 on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t0" "t[1-7]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -0 t0 works' ' $powerman -h $testaddr -0 t0 >off.out && echo Command completed successfully >off.exp && test_cmp off.exp off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query3.out && makeoutput "" "t[0-7]" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'powerman -1 t[0-7] works' ' $powerman -h $testaddr -1 t[0-7] >on2.out && echo Command completed successfully >on2.exp && test_cmp on2.exp on2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query4.out && makeoutput "t[0-7]" "" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -c t[0-7] works' ' $powerman -h $testaddr -c t[0-7] >cycle2.out && echo Command completed successfully >cycle2.exp && test_cmp cycle2.exp cycle2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query4.out && makeoutput "t[0-7]" "" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -0 t[0-7] works' ' $powerman -h $testaddr -0 t[0-7] >off2.out && echo Command completed successfully >off2.exp && test_cmp off2.exp off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query5.out && makeoutput "" "t[0-7]" "" >query5.exp && test_cmp query5.exp query5.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0021-remote-powerman.t000077500000000000000000000106501467035776500177170ustar00rootroot00000000000000#!/bin/sh test_description='Check powermand as a power control device' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman vpcd=$SHARNESS_BUILD_DIRECTORY/t/simulators/vpcd vpcdev=$SHARNESS_TEST_SRCDIR/etc/vpc.dev powermandev=$SHARNESS_TEST_SRCDIR/../etc/devices/powerman.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11021 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create controlled powerman.conf with 4 devices (64 plugs)' ' cat >rpowerman.conf <<-EOT include "$vpcdev" device "test0" "vpc" "$vpcd |&" device "test1" "vpc" "$vpcd |&" device "test2" "vpc" "$vpcd |&" device "test3" "vpc" "$vpcd |&" node "t[0-15]" "test0" node "t[16-31]" "test1" node "t[32-47]" "test2" node "t[48-63]" "test3" EOT ' test_expect_success 'create controlling powerman.conf' ' cat >powerman.conf <<-EOT listen "$testaddr" include "$powermandev" device "p0" "powerman" "$powermand --stdio -c rpowerman.conf |&" node "t[0-63]" "p0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' SET1="t[0,8,16,24,32,40,48,56]" SET2="t[1-7,9-15,17-23,25-31,33-39,41-47,49-55,57-63]" test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query.out && makeoutput "" "t[0-63]" "" >query.exp && test_cmp query.exp query.out ' test_expect_success "powerman -1 $SET1 works" ' $powerman -h $testaddr -1 $SET1 >on.out && echo Command completed successfully >on.exp && test_cmp on.exp on.out ' test_expect_success 'powerman -q shows expected result' ' $powerman -h $testaddr -q >query2.out && makeoutput "$SET1" "$SET2" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success "powerman -c $SET1 works" ' $powerman -h $testaddr -c $SET1 >cycle.out && echo Command completed successfully >cycle.exp && test_cmp cycle.exp cycle.out ' test_expect_success 'powerman -q shows expected result' ' $powerman -h $testaddr -q >query2.out && makeoutput "$SET1" "$SET2" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success "powerman -0 $SET1 works" ' $powerman -h $testaddr -0 $SET1 >off.out && echo Command completed successfully >off.exp && test_cmp off.exp off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query3.out && makeoutput "" "t[0-63]" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success "powerman -r $SET1 works" ' $powerman -h $testaddr -r $SET1 >reset.out && echo Command completed successfully >reset.exp && test_cmp reset.exp reset.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query4.out && makeoutput "" "t[0-63]" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -1 t[0-63] works' ' $powerman -h $testaddr -1 t[0-63] >on2.out && echo Command completed successfully >on2.exp && test_cmp on2.exp on2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query5.out && makeoutput "t[0-63]" "" "" >query5.exp && test_cmp query5.exp query5.out ' test_expect_success 'powerman -c t[0-63] works' ' $powerman -h $testaddr -c t[0-63] >cycle2.out && echo Command completed successfully >cycle2.exp && test_cmp cycle2.exp cycle2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query6.out && makeoutput "t[0-63]" "" "" >query6.exp && test_cmp query6.exp query6.out ' test_expect_success 'powerman -0 t[0-63] works' ' $powerman -h $testaddr -0 t[0-63] >off2.out && echo Command completed successfully >off2.exp && test_cmp off2.exp off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query7.out && makeoutput "" "t[0-63]" "" >query7.exp && test_cmp query7.exp query7.out ' test_expect_success 'powerman -r t[0-63] works' ' $powerman -h $testaddr -r t[0-63] >reset2.out && echo Command completed successfully >reset2.exp && test_cmp reset2.exp reset2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query8.out && makeoutput "" "t[0-63]" "" >query8.exp && test_cmp query8.exp query8.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0023-sun-microsystems-ilom.t000077500000000000000000000060771467035776500211120ustar00rootroot00000000000000#!/bin/sh test_description='Check Sun Microsystems ilom and lom devices' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman ilom=$SHARNESS_BUILD_DIRECTORY/t/simulators/ilom lom=$SHARNESS_BUILD_DIRECTORY/t/simulators/lom ilomdev=$SHARNESS_TEST_SRCDIR/../etc/devices/ilom.dev lomdev=$SHARNESS_TEST_SRCDIR/../etc/devices/lom.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11023 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create powerman.conf for lom + ilom devices (6 plugs)' ' cat >powerman.conf <<-EOT listen "$testaddr" include "$ilomdev" include "$lomdev" device "d0" "ilom" "$ilom -p ssh |&" device "d1" "ilom" "$ilom -p serial |&" device "d2" "ilom" "$ilom -p serial_loggedin |&" device "d3" "lom" "$lom -p ssh |&" device "d4" "lom" "$lom -p serial |&" device "d5" "lom" "$lom -p serial_loggedin |&" node "t0" "d0" node "t1" "d1" node "t2" "d2" node "t3" "d3" node "t4" "d4" node "t5" "d5" alias "iloms" "t[0-2]" alias "loms" "t[3-5]" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query.out && makeoutput "" "t[0-5]" "" >query.exp && test_cmp query.exp query.out ' test_expect_success 'powerman -1 t[0-5] works' ' $powerman -h $testaddr -1 t[0-5] >on.out && echo Command completed successfully >on.exp && test_cmp on.exp on.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t[0-5]" "" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -c t[0-5] works' ' $powerman -h $testaddr -c t[0-5] >cycle.out && echo Command completed successfully >cycle.exp && test_cmp cycle.exp cycle.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t[0-5]" "" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -0 t[0-5] works' ' $powerman -h $testaddr -0 t[0-5] >off.out && echo Command completed successfully >off.exp && test_cmp off.exp off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query3.out && makeoutput "" "t[0-5]" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'powerman -r iloms works' ' $powerman -h $testaddr -r iloms >reset.out && echo Command completed successfully >reset.exp && test_cmp reset.exp reset.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query4.out && makeoutput "" "t[0-5]" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -r loms fails' ' test_must_fail $powerman -h $testaddr -r loms ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0024-freeipmi.t000077500000000000000000000050771467035776500164100ustar00rootroot00000000000000#!/bin/sh test_description='Check FreeIPMI ipmipower device' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman ipmipower=$SHARNESS_BUILD_DIRECTORY/t/simulators/ipmipower ipmipowerdev=$SHARNESS_TEST_SRCDIR/../etc/devices/ipmipower.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11024 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create powerman.conf one ipmipower device (16 nodes)' ' cat >powerman.conf <<-EOT listen "$testaddr" include "$ipmipowerdev" device "d0" "ipmipower" "$ipmipower -h t[0-15] |&" node "t[0-15]" "d0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query.out && makeoutput "" "t[0-15]" "" >query.exp && test_cmp query.exp query.out ' test_expect_success 'powerman -1 t[0,8] works' ' $powerman -h $testaddr -1 t[0,8] >on.out && echo Command completed successfully >on.exp && test_cmp on.exp on.out ' test_expect_success 'powerman -q shows t[0,8] on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t[0,8]" "t[1-7,9-15]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -0 t[0,8] works' ' $powerman -h $testaddr -0 t[0,8] >off.out && echo Command completed successfully >off.exp && test_cmp off.exp off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query2.out && makeoutput "" "t[0-15]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -1 t[0-15] works' ' $powerman -h $testaddr -1 t[0-15] >on2.out && echo Command completed successfully >on2.exp && test_cmp on2.exp on2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query3.out && makeoutput "t[0-15]" "" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'powerman -0 t[0-15] works' ' $powerman -h $testaddr -0 t[0-15] >off2.out && echo Command completed successfully >off2.exp && test_cmp off2.exp off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query4.out && makeoutput "" "t[0-15]" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0025-openbmc.t000077500000000000000000000046331467035776500162310ustar00rootroot00000000000000#!/bin/sh test_description='Check openbmc device' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman openbmc=$SHARNESS_BUILD_DIRECTORY/t/simulators/openbmc-httppower openbmcdev=$SHARNESS_TEST_SRCDIR/../etc/devices/openbmc.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11025 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create powerman.conf for 5 openbmc nodes' ' cat >powerman.conf <<-EOT listen "$testaddr" include "$openbmcdev" device "d0" "openbmc" "$openbmc |&" device "d1" "openbmc" "$openbmc |&" device "d2" "openbmc" "$openbmc |&" device "d3" "openbmc" "$openbmc |&" device "d4" "openbmc" "$openbmc |&" node "t0" "d0" "t0" node "t1" "d1" "t1" node "t2" "d2" "t2" node "t3" "d3" "t3" node "t4" "d4" "t4" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query.out && makeoutput "" "t[0-4]" "" >query.exp && test_cmp query.exp query.out ' test_expect_success 'powerman -1 t[0-4] works' ' $powerman -h $testaddr -1 t[0-4] >on.out && echo Command completed successfully >on.exp && test_cmp on.exp on.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t[0-4]" "" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -0 t[0-4] works' ' $powerman -h $testaddr -0 t[0-4] >off.out && echo Command completed successfully >off.exp && test_cmp off.exp off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query2.out && makeoutput "" "t[0-4]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -c t[0-4] works' ' $powerman -h $testaddr -c t[0-4] >cycle.out && echo Command completed successfully >cycle.exp && test_cmp cycle.exp cycle.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query3.out && makeoutput "t[0-4]" "" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0026-llnl-sierra-cluster.t000077500000000000000000000135721467035776500205140ustar00rootroot00000000000000#!/bin/sh test_description='Check LLNL sierra cluster config with IPMI + PDU This was a Dell cluster named sierra, circa 2010, not to be confused with the IBM cluster named sierra, sited in 2018. See also: chaos/powerman#115. ' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman swpdu=$SHARNESS_BUILD_DIRECTORY/t/simulators/swpdu ipmipower=$SHARNESS_BUILD_DIRECTORY/t/simulators/ipmipower ipmipowerdev=$SHARNESS_TEST_SRCDIR/../etc/devices/ipmipower.dev swpdudev=$SHARNESS_TEST_SRCDIR/../etc/devices/swpdu.dev plugconf=$SHARNESS_TEST_SRCDIR/etc/sierra_plugs.conf # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11026 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } # This config was adapted from the actual sierra config, where chassis # had PDU power control and blades had IPMI power control. test_expect_success 'create powerman.conf for sierra' ' cat >powerman.conf <<-EOT listen "$testaddr" include "$ipmipowerdev" include "$swpdudev" device "ipmi0" "ipmipower" "$ipmipower -h psierra[0,2-143] |&" device "ipmi1" "ipmipower" "$ipmipower -h psierra[144-287] |&" device "ipmi2" "ipmipower" "$ipmipower -h psierra[288-431] |&" device "ipmi3" "ipmipower" "$ipmipower -h psierra[432-575] |&" device "ipmi4" "ipmipower" "$ipmipower -h psierra[576-719] |&" device "ipmi5" "ipmipower" "$ipmipower -h psierra[720-863] |&" device "ipmi6" "ipmipower" "$ipmipower -h psierra[864-1007] |&" device "ipmi7" "ipmipower" "$ipmipower -h psierra[1008-1151] |&" device "ipmi8" "ipmipower" "$ipmipower -h psierra[1152-1295] |&" device "ipmi9" "ipmipower" "$ipmipower -h psierra[1296-1439] |&" device "ipmi10" "ipmipower" "$ipmipower -h psierra[1440-1583] |&" device "ipmi11" "ipmipower" "$ipmipower -h psierra[1584-1727] |&" device "ipmi12" "ipmipower" "$ipmipower -h psierra[1728-1871] |&" device "ipmi13" "ipmipower" "$ipmipower -h psierra[1872-1943] |&" device "pdu1" "swpdu" "$swpdu |&" device "pdu2" "swpdu" "$swpdu |&" device "pdu3" "swpdu" "$swpdu |&" device "pdu4" "swpdu" "$swpdu |&" device "pdu5" "swpdu" "$swpdu |&" device "pdu6" "swpdu" "$swpdu |&" device "pdu7" "swpdu" "$swpdu |&" device "pdu8" "swpdu" "$swpdu |&" device "pdu9" "swpdu" "$swpdu |&" device "pdu10" "swpdu" "$swpdu |&" device "pdu11" "swpdu" "$swpdu |&" device "pdu12" "swpdu" "$swpdu |&" device "pdu13" "swpdu" "$swpdu |&" device "pdu14" "swpdu" "$swpdu |&" device "pdu15" "swpdu" "$swpdu |&" #device "pdu16" "swpdu" "$swpdu |&" #device "pdu17" "swpdu" "$swpdu |&" #device "pdu18" "swpdu" "$swpdu |&" device "pdu19" "swpdu" "$swpdu |&" device "pdu20" "swpdu" "$swpdu |&" device "pdu21" "swpdu" "$swpdu |&" device "pdu22" "swpdu" "$swpdu |&" device "pdu23" "swpdu" "$swpdu |&" device "pdu24" "swpdu" "$swpdu |&" device "pdu25" "swpdu" "$swpdu |&" device "pdu26" "swpdu" "$swpdu |&" device "pdu27" "swpdu" "$swpdu |&" device "pdu28" "swpdu" "$swpdu |&" device "pdu29" "swpdu" "$swpdu |&" device "pdu30" "swpdu" "$swpdu |&" device "pdu31" "swpdu" "$swpdu |&" device "pdu32" "swpdu" "$swpdu |&" device "pdu33" "swpdu" "$swpdu |&" include "$plugconf" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman.conf >powermand.out 2>powermand.err & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d >device.out ' test_expect_success 'powerman -q sierra[0,2-1943] shows all blades off' ' $powerman -h $testaddr -q sierra[0,2-1943] >query_blades.out && makeoutput "" "sierra[0,2-1943]" "" >query_blades.exp && test_cmp query_blades.exp query_blades.out ' # Messy off: line so just verify that "unknown" and "on" are empty test_expect_success 'powerman -q chassis[1-468] shows all chassis off' ' $powerman -h $testaddr -q chassis[1-468] >query_chassis.out && grep -q "unknown: $" query_chassis.out && grep -q "on: $" query_chassis.out ' test_expect_success 'powerman -1 chassis[1-468] works' ' $powerman -h $testaddr -1 chassis[1-468] >on_chassis.out && echo Command completed successfully >on_chassis.exp && test_cmp on_chassis.exp on_chassis.out ' test_expect_success 'powerman -q chassis[1-468] shows all chassis on' ' $powerman -h $testaddr -q chassis[1-468] >query_chassis2.out && grep -q "unknown: $" query_chassis2.out && grep -q "off: $" query_chassis2.out ' test_expect_success 'powerman -1 sierra[0,2-1943] works' ' $powerman -h $testaddr -1 sierra[0,2-1943] >on_blades.out && echo Command completed successfully >on_blades.exp && test_cmp on_blades.exp on_blades.out ' test_expect_success 'powerman -q sierra[0,2-1943] shows all blades on' ' $powerman -h $testaddr -q sierra[0,2-1943] >query_blades2.out && makeoutput "sierra[0,2-1943]" "" "" >query_blades2.exp && test_cmp query_blades2.exp query_blades2.out ' test_expect_success 'powerman -0 sierra[0,2-1943] works' ' $powerman -h $testaddr -0 sierra[0,2-1943] >off_blades.out && echo Command completed successfully >off_blades.exp && test_cmp off_blades.exp off_blades.out ' test_expect_success 'powerman -q sierra[0,2-1943] shows all blades off' ' $powerman -h $testaddr -q sierra[0,2-1943] >query_blades3.out && makeoutput "" "sierra[0,2-1943]" "" >query_blades3.exp && test_cmp query_blades3.exp query_blades3.out ' test_expect_success 'powerman -0 chassis[1-468] works' ' $powerman -h $testaddr -0 chassis[1-468] >off_chassis.out && echo Command completed successfully >off_chassis.exp && test_cmp off_chassis.exp off_chassis.out ' test_expect_success 'powerman -q chassis[1-468] shows all chassis off' ' $powerman -h $testaddr -q chassis[1-468] >query_chassis3.out && grep -q "unknown: $" query_chassis3.out && grep -q "on: $" query_chassis3.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0027-redfish-httppower.t000077500000000000000000000051121467035776500202570ustar00rootroot00000000000000#!/bin/sh test_description='Check redfish-supermicro device which uses httppower' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman simdir=$SHARNESS_BUILD_DIRECTORY/t/simulators devicesdir=$SHARNESS_TEST_SRCDIR/../etc/devices # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11027 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create powerman.conf for 5 redfish-supermicro nodes' ' cat >powerman.conf <<-EOT listen "$testaddr" include "$devicesdir/redfish-supermicro.dev" device "d0" "redfish-supermicro" "$simdir/redfish-httppower |&" device "d1" "redfish-supermicro" "$simdir/redfish-httppower |&" device "d2" "redfish-supermicro" "$simdir/redfish-httppower |&" device "d3" "redfish-supermicro" "$simdir/redfish-httppower |&" device "d4" "redfish-supermicro" "$simdir/redfish-httppower |&" node "t0" "d0" "t0" node "t1" "d1" "t1" node "t2" "d2" "t2" node "t3" "d3" "t3" node "t4" "d4" "t4" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query.out && makeoutput "" "t[0-4]" "" >query.exp && test_cmp query.exp query.out ' test_expect_success 'powerman -1 t[0-4] works' ' $powerman -h $testaddr -1 t[0-4] >on.out && echo Command completed successfully >on.exp && test_cmp on.exp on.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t[0-4]" "" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -0 t[0-4] works' ' $powerman -h $testaddr -0 t[0-4] >off.out && echo Command completed successfully >off.exp && test_cmp off.exp off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query2.out && makeoutput "" "t[0-4]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -c t[0-4] works' ' $powerman -h $testaddr -c t[0-4] >cycle.out && echo Command completed successfully >cycle.exp && test_cmp cycle.exp cycle.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query3.out && makeoutput "t[0-4]" "" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0028-issues.t000077500000000000000000000062501467035776500161210ustar00rootroot00000000000000#!/bin/sh test_description='Check that fixes to issues stay fixed' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman devicesdir=$SHARNESS_TEST_SRCDIR/../etc/devices simdir=$SHARNESS_BUILD_DIRECTORY/t/simulators vpcd=$simdir/vpcd vpcdev=$SHARNESS_TEST_SRCDIR/etc/vpc.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11028 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } # https://code.google.com/archive/p/powerman/issues/3 test_expect_success 'gc#3: make bad config to check error has correct line no' ' cat >powerman_gc3.dev<<-EOT && # 1 # 2 # 3 # 4 syntaxerror # 5 # 6 # 7 EOT cat >powerman_gc3.conf <<-EOT2 # comment include "$vpcdev" # comment include "powerman_gc3.dev" EOT2 ' test_expect_success 'gc#3: correct line number is called out' ' test_must_fail $powermand -Y -c powerman_gc3.conf 2>gc3.err && grep "parse error: powerman_gc3.dev::5" gc3.err ' # https://code.google.com/archive/p/powerman/issues/34 test_expect_success 'gc#34: create config that triggered duplicate node name' ' cat >powerman_gc34.conf <<-EOT listen "$testaddr" include "$vpcdev" device "linkfarm" "vpc" "$vpcd |&" device "mds" "vpc" "$vpcd |&" node "widow-mds" "linkfarm" "1" node "widow-mds[0-3]" "mds" "[2-5]" EOT ' test_expect_success 'gc#34: powermand starts ok' ' $powermand -Y -c powerman_gc34.conf & echo $! >powermand_gc34.pid && $powerman --retry-connect=100 --server-host=$testaddr -q ' test_expect_success 'gc#34: stop powerman daemon' ' kill -15 $(cat powermand_gc34.pid) && wait ' # https://code.google.com/archive/p/powerman/issues/35 test_expect_success 'gc#35: create another config that triggered duplicate node name' ' cat >powerman_gc35.conf <<-EOT listen "$testaddr" include "$vpcdev" device "pdu1" "vpc" "$vpcd |&" node "corn1-p2" "pdu1" "1" node "corn2" "pdu1" "2" EOT ' test_expect_success 'gc#35: powermand starts ok' ' $powermand -Y -c powerman_gc35.conf & echo $! >powermand_gc35.pid && $powerman --retry-connect=100 --server-host=$testaddr -q ' test_expect_success 'gc#35: stop powerman daemon' ' kill -15 $(cat powermand_gc35.pid) && wait ' # chaos/powerman#14 # N.B. --auth-failure will make the first node report "password verification # timeout", which should lead to unknown state test_expect_success 'issue#14: create config for ipmipower auth parse error' ' cat >powerman_issue14.conf <<-EOT listen "$testaddr" include "$devicesdir/ipmipower.dev" device "d0" "ipmipower" "$simdir/ipmipower --auth-failure -h t[0-15] |&" node "t[0-15]" "d0" EOT ' test_expect_success 'issue#14: powermand starts ok and answers query' ' $powermand -Y -c powerman_issue14.conf & echo $! >powermand_issue14.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >issue14.out ' test_expect_success 'issue#14: power state of auth failure node is unknown' ' makeoutput "" "t[1-15]" "t0" >issue14.exp && test_cmp issue14.exp issue14.out ' test_expect_success 'issue#14: stop powerman daemon' ' kill -15 $(cat powermand_issue14.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0029-redfish.t000077500000000000000000000065131467035776500162350ustar00rootroot00000000000000#!/bin/sh test_description='Check redfishpower devices' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman redfishdir=$SHARNESS_BUILD_DIRECTORY/src/redfishpower devicesdir=$SHARNESS_TEST_SRCDIR/../etc/devices # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11029 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } # # redfishpower core tests # test_expect_success 'create powerman.conf for 16 cray redfish nodes' ' cat >powerman.conf <<-EOT listen "$testaddr" include "$devicesdir/redfishpower-cray-r272z30.dev" device "d0" "redfishpower-cray-r272z30" "$redfishdir/redfishpower -h t[0-15] --test-mode |&" node "t[0-15]" "d0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query.out && makeoutput "" "t[0-15]" "" >query.exp && test_cmp query.exp query.out ' test_expect_success 'powerman -1 t[0,8] works' ' $powerman -h $testaddr -1 t[0,8] >on.out && echo Command completed successfully >on.exp && test_cmp on.exp on.out ' test_expect_success 'powerman -q shows t[0,8] on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t[0,8]" "t[1-7,9-15]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -0 t[0,8] works' ' $powerman -h $testaddr -0 t[0,8] >off.out && echo Command completed successfully >off.exp && test_cmp off.exp off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query2.out && makeoutput "" "t[0-15]" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -1 t[0-15] works' ' $powerman -h $testaddr -1 t[0-15] >on2.out && echo Command completed successfully >on2.exp && test_cmp on2.exp on2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query3.out && makeoutput "t[0-15]" "" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'powerman -0 t[0-15] works' ' $powerman -h $testaddr -0 t[0-15] >off2.out && echo Command completed successfully >off2.exp && test_cmp off2.exp off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query4.out && makeoutput "" "t[0-15]" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -c t[0-15] works' ' $powerman -h $testaddr -c t[0-15] >cycle.out && echo Command completed successfully >cycle.exp && test_cmp cycle.exp cycle.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query5.out && makeoutput "t[0-15]" "" "" >query5.exp && test_cmp query5.exp query5.out ' test_expect_success 'powerman -c t[0-15] works again' ' $powerman -h $testaddr -c t[0-15] >cycle2.out && echo Command completed successfully >cycle2.exp && test_cmp cycle2.exp cycle2.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query6.out && makeoutput "t[0-15]" "" "" >query6.exp && test_cmp query6.exp query6.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0030-heartbeat-stonith.t000077500000000000000000000073211467035776500202240ustar00rootroot00000000000000#!/bin/sh test_description='Check heartbeat stonith script for powerman' . `dirname $0`/sharness.sh export pm_sim=$SHARNESS_TEST_SRCDIR/scripts/pm-sim.sh export stonith=$SHARNESS_TEST_SRCDIR/../heartbeat/powerman echo "Command completed successfully" >success.exp is_successful() { test_cmp success.exp $1 } # The stonith script is a plugin to heartbeat(8) which enables high # availability configurations to use powerman to power off members of # a failover pair. The plugin is just a shell script that behaves in # a pre-defined way. These tests verify that the shell script exhibits # the expected behaviors and does the right thing when powerman fails. # It does so by setting $PM_OVERRIDE to point to a script that emulates # powerman, rather than by setting up a real powerman environment in test. # The script makes it possible to alter powerman's behavior in ways that # would be inconvenient in the real thing. test_expect_success 'reset simulated state' ' rm -f pm-sim.data ' test_expect_success 'single plug: stonith on t works' ' PM_OVERRIDE=$pm_sim PM_VERBOSE=1 \ $stonith on t >on.out 2>on.err && is_successful on.out && cat >on_err.exp <<-EOT && powerman-stonith: $pm_sim -1 t, rc=0 EOT test_cmp on_err.exp on.err ' test_expect_success 'single plug stonith off t works' ' PM_OVERRIDE=$pm_sim PM_VERBOSE=1 \ $stonith off t >off.out 2>off.err && is_successful off.out && cat >off_err.exp <<-EOT && powerman-stonith: $pm_sim -0 t, rc=0 powerman-stonith: $pm_sim -q t, state=off, rc=0 EOT test_cmp off_err.exp off.err ' test_expect_success 'reset simulated state' ' rm -f pm-sim.data ' test_expect_success 'aliased plug: stonith on t works' ' PM_OVERRIDE="$pm_sim -A" PM_VERBOSE=1 \ $stonith on t >onA.out 2>onA.err && is_successful onA.out && cat >onA_err.exp <<-EOT && powerman-stonith: $pm_sim -A -1 t, rc=0 EOT test_cmp onA_err.exp onA.err ' test_expect_success 'aliased plug: stonith off t works' ' PM_OVERRIDE="$pm_sim -A" PM_VERBOSE=1 \ $stonith off t >offA.out 2>offA.err && is_successful offA.out && cat >offA_err.exp <<-EOT && powerman-stonith: $pm_sim -A -0 t, rc=0 powerman-stonith: $pm_sim -A -q t, state=off, rc=0 EOT test_cmp offA_err.exp offA.err ' test_expect_success 'reset simulated state' ' rm -f pm-sim.data ' test_expect_success 'single plug stonith on t works' ' PM_OVERRIDE=$pm_sim PM_VERBOSE=1 \ $stonith on t >on2.out 2>on2.err && is_successful on2.out && cat >on2_err.exp <<-EOT && powerman-stonith: $pm_sim -1 t, rc=0 EOT test_cmp on2_err.exp on2.err ' test_expect_success 'single plug simulated off failure is detected' ' (export PM_OVERRIDE="$pm_sim -r -s -t"; export PM_VERBOSE=1; \ test_must_fail $stonith off t) >off_fail.out 2>off_fail.err && is_successful off_fail.out && cat >off_fail_err.exp <<-EOT && powerman-stonith: $pm_sim -r -s -t -0 t, rc=0 powerman-stonith: $pm_sim -r -s -t -q t, state=unknown, rc=1 EOT test_cmp off_fail_err.exp off_fail.err ' test_expect_success 'reset simulated state' ' rm -f pm-sim.data ' test_expect_success 'aliased plug stonith on t works' ' PM_OVERRIDE="$pm_sim -A" PM_VERBOSE=1 \ $stonith on t >onA2.out 2>onA2.err && is_successful onA2.out && cat >onA2_err.exp <<-EOT && powerman-stonith: $pm_sim -A -1 t, rc=0 EOT test_cmp onA2_err.exp onA2.err ' test_expect_success 'aliased plug simulated off failure is detected' ' (export PM_OVERRIDE="$pm_sim -A -r -s -t"; export PM_VERBOSE=1; \ test_must_fail $stonith off t) >offA_fail.out 2>offA_fail.err && is_successful offA_fail.out && cat >offA_fail_err.exp <<-EOT && powerman-stonith: $pm_sim -A -r -s -t -0 t, rc=0 powerman-stonith: $pm_sim -A -r -s -t -q t, state=unknown, rc=1 EOT test_cmp offA_fail_err.exp offA_fail.err ' test_done # vi: set ft=sh powerman-2.4.4/t/t0031-llnl-mcr-cluster.t000077500000000000000000000211361467035776500177770ustar00rootroot00000000000000#!/bin/sh test_description='Check LLNL MCR config with many icebox v3 devices' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman simdir=$SHARNESS_BUILD_DIRECTORY/t/simulators devicedir=$SHARNESS_TEST_SRCDIR/../etc/devices plugconf=$SHARNESS_TEST_SRCDIR/etc/mcr_plugs.conf # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11031 echo "Command completed successfully" >success.exp is_successful() { test_cmp success.exp $1 } makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } # This config was adapted from the actual MCR config. This machine was a # node count scaling milestone for early Linux clusters at LLNL and thus # became a sandbox during pre-production integration for improving the lab's # Linux system system, including powerman. test_expect_success 'create powerman.conf for MCR' ' cat >powerman.conf <<-EOT listen "$testaddr" include "$devicedir/icebox3.dev" device "ice-r1-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r2-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r4-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r5-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r6-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r7-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r7-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r7-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r8-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r8-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r8-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r9-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r9-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r9-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r9-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r10-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r10-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r11-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r11-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r11-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r11-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r15-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r15-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r15-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r15-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r16-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r16-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r17-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r17-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r17-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r17-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r18-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r18-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r18-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r18-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r19-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r19-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r20-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r20-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r20-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r20-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r23-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r23-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r23-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r23-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r24-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r24-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r25-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r25-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r25-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r25-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r26-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r26-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r26-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r26-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r27-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r27-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r28-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r28-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r28-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r28-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r29-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r29-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r29-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r29-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r30-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r30-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r31-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r31-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r31-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r31-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r32-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r32-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r32-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r32-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r33-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r33-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r34-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r34-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r34-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r34-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r35-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r35-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r35-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r35-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r36-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r36-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r37-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r37-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r37-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r37-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r38-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r38-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r38-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r38-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r39-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r39-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r40-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r40-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r40-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r40-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r41-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r41-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r41-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r41-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r42-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r42-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r43-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r43-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r43-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r43-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r12-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r12-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r12-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r12-4" "icebox3" "$simdir/icebox -pv3|&" device "ice-r13-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r13-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r14-1" "icebox3" "$simdir/icebox -pv3|&" device "ice-r14-2" "icebox3" "$simdir/icebox -pv3|&" device "ice-r14-3" "icebox3" "$simdir/icebox -pv3|&" device "ice-r14-4" "icebox3" "$simdir/icebox -pv3|&" include "$plugconf" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman.conf >powermand.out 2>powermand.err & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d >device.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query.out && makeoutput "" "mcr[0-1151],mcrj" "" >query.exp && test_cmp query.exp query.out ' test_expect_success 'powerman -1 mcr[0-1151],mcrj works' ' $powerman -h $testaddr -1 mcr[0-1151],mcrj >on.out && is_successful on.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query2.out && makeoutput "mcr[0-1151],mcrj" "" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -0 mcr[0-1151],mcrj works' ' $powerman -h $testaddr -0 mcr[0-1151],mcrj >off.out && is_successful off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query3.out && makeoutput "" "mcr[0-1151],mcrj" "" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0032-list.t000077500000000000000000000023561467035776500155570ustar00rootroot00000000000000#!/bin/sh test_description='Test Powerman list query' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman vpcd=$SHARNESS_BUILD_DIRECTORY/t/simulators/vpcd vpcdev=$SHARNESS_TEST_SRCDIR/etc/vpc.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11032 test_expect_success 'create test powerman.conf' ' cat >powerman.conf <<-EOT include "$vpcdev" listen "$testaddr" device "test0" "vpc" "$vpcd |&" node "t[0-15]" "test0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d >/dev/null ' test_expect_success 'powerman -l works' ' $powerman -h $testaddr -l >list.out && echo "t[0-15]" >list.exp && test_cmp list.exp list.out ' test_expect_success 'powerman -l fails with targets' ' test_must_fail $powerman -h $testaddr -l t2 2>list.err ' test_expect_success 'and a useful message was printed on stderr' ' grep "does not accept targets" list.err ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0033-valgrind.t000077500000000000000000000017771467035776500164210ustar00rootroot00000000000000#!/bin/sh test_description='Test Powerman list query' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman vpcd=$SHARNESS_BUILD_DIRECTORY/t/simulators/vpcd vpcdev=$SHARNESS_TEST_SRCDIR/etc/vpc.dev suppressions=$SHARNESS_TEST_SRCDIR/etc/valgrind.supp # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11033 if ! valgrind --version; then skip_all='skipping valgrind tests' test_done fi test_expect_success 'create test powerman.conf' ' cat >powerman.conf <<-EOT include "$vpcdev" listen "$testaddr" device "test0" "vpc" "$vpcd |&" node "t[0-15]" "test0" alias "a0" "t0" EOT ' test_expect_success 'run powermand --stdio under valgrind' ' valgrind --tool=memcheck --leak-check=full --error-exitcode=1 \ --gen-suppressions=all --suppressions=$suppressions \ $powermand --stdio -c powerman.conf 2>valgrind.err <<-EOT help EOT ' test_done # vi: set ft=sh powerman-2.4.4/t/t0034-redfishpower.t000077500000000000000000000760431467035776500173130ustar00rootroot00000000000000#!/bin/sh test_description='Cover redfishpower specific configurations' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman redfishdir=$SHARNESS_BUILD_DIRECTORY/src/redfishpower devicesdir=$SHARNESS_TEST_SRCDIR/../etc/devices testdevicesdir=$SHARNESS_TEST_SRCDIR/etc # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11034 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } # # redfishpower fail hosts coverage # test_expect_success 'create powerman.conf for 16 cray redfish nodes (failhosts)' ' cat >powerman_fail_hosts.conf <<-EOT listen "$testaddr" include "$devicesdir/redfishpower-cray-r272z30.dev" device "d0" "redfishpower-cray-r272z30" "$redfishdir/redfishpower -h t[0-15] --test-mode --test-fail-power-cmd-hosts=t[8-15] |&" node "t[0-15]" "d0" EOT ' test_expect_success 'start powerman daemon and wait for it to start (failhosts)' ' $powermand -Y -c powerman_fail_hosts.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows t[0-7] off, t[8-15] unknown' ' $powerman -h $testaddr -q >test_failhosts_query.out && makeoutput "" "t[0-7]" "t[8-15]" >test_failhosts_query.exp && test_cmp test_failhosts_query.exp test_failhosts_query.out ' test_expect_success 'powerman -1 t[0-15] completes' ' $powerman -h $testaddr -1 t[0-15] >test_failhosts_on.out && echo Command completed successfully >test_failhosts_on.exp && test_cmp test_failhosts_on.exp test_failhosts_on.out ' test_expect_success 'powerman -q shows t[0-7] on' ' $powerman -h $testaddr -q >test_failhosts_query2.out && makeoutput "t[0-7]" "" "t[8-15]" >test_failhosts_query2.exp && test_cmp test_failhosts_query2.exp test_failhosts_query2.out ' test_expect_success 'stop powerman daemon (failhosts)' ' kill -15 $(cat powermand.pid) && wait ' # # redfishpower setplugs coverage # test_expect_success 'create powerman.conf for 16 cray redfish nodes (setplugs)' ' cat >powerman_setplugs.conf <<-EOT listen "$testaddr" include "$testdevicesdir/redfishpower-setplugs.dev" device "d0" "redfishpower-setplugs" "$redfishdir/redfishpower -h t[0-15] --test-mode |&" node "t[0-15]" "d0" "Node[0-15]" EOT ' test_expect_success 'start powerman daemon and wait for it to start (setplugs)' ' $powermand -Y -c powerman_setplugs.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_setplugs_query.out && makeoutput "" "t[0-15]" "" >test_setplugs_query.exp && test_cmp test_setplugs_query.exp test_setplugs_query.out ' test_expect_success 'powerman -T -q shows plugs are being used' ' $powerman -h $testaddr -T -q > test_setplugs_query_T.out && grep "Node15: off" test_setplugs_query_T.out ' test_expect_success 'powerman -1 t[0-15] works' ' $powerman -h $testaddr -1 t[0-15] >test_setplugs_on.out && echo Command completed successfully >test_setplugs_on.exp && test_cmp test_setplugs_on.exp test_setplugs_on.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >test_setplugs_query2.out && makeoutput "t[0-15]" "" "" >test_setplugs_query2.exp && test_cmp test_setplugs_query2.exp test_setplugs_query2.out ' test_expect_success 'stop powerman daemon (setplugs)' ' kill -15 $(cat powermand.pid) && wait ' # # redfishpower setpath coverage # test_expect_success 'create powerman.conf for 16 cray redfish nodes (setpath)' ' cat >powerman_setpath.conf <<-EOT listen "$testaddr" include "$testdevicesdir/redfishpower-setpath.dev" device "d0" "redfishpower-setpath" "$redfishdir/redfishpower -h t[0-15] --test-mode |&" node "t[0-15]" "d0" "Node[0-15]" EOT ' test_expect_success 'start powerman daemon and wait for it to start (setpath' ' $powermand -Y -c powerman_setpath.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_setpath_query.out && makeoutput "" "t[0-15]" "" >test_setpath_query.exp && test_cmp test_setpath_query.exp test_setpath_query.out ' test_expect_success 'powerman -1 t[0-15] works' ' $powerman -h $testaddr -1 t[0-15] >test_setpath_on.out && echo Command completed successfully >test_setpath_on.exp && test_cmp test_setpath_on.exp test_setpath_on.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >test_setpath_query2.out && makeoutput "t[0-15]" "" "" >test_setpath_query2.exp && test_cmp test_setpath_query2.exp test_setpath_query2.out ' test_expect_success 'stop powerman daemon (setpath)' ' kill -15 $(cat powermand.pid) && wait ' # Note, verbose output can mess up the device script's interpretation of power status, # so restart powermand with verbose mode to run telemetry specific tests. test_expect_success 'create powerman.conf for 16 cray redfish nodes (setpath2)' ' cat >powerman_setpath2.conf <<-EOT listen "$testaddr" include "$testdevicesdir/redfishpower-setpath.dev" device "d0" "redfishpower-setpath" "$redfishdir/redfishpower -h t[0-15] --test-mode -vv |&" node "t[0-15]" "d0" "Node[0-15]" EOT ' test_expect_success 'start powerman daemon and wait for it to start (setpath2)' ' $powermand -Y -c powerman_setpath2.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' # Note: redfishpower-setpath.dev sets different paths for different # nodes. Following tests check that correct path has been used. test_expect_success 'powerman -T -1 shows correct path being used (t0)' ' $powerman -h $testaddr -T -1 t0 > test_setpath2_on_T1.out && grep "plugname=Node0" test_setpath2_on_T1.out | grep "path=" | grep Group0 ' test_expect_success 'powerman -T -1 shows correct path being used (t5)' ' $powerman -h $testaddr -T -1 t5 > test_setpath2_on_T2.out && grep "plugname=Node5" test_setpath2_on_T2.out | grep "path=" | grep Group1 ' test_expect_success 'powerman -T -1 shows correct path being used (t10)' ' $powerman -h $testaddr -T -1 t10 > test_setpath2_on_T3.out && grep "plugname=Node10" test_setpath2_on_T3.out | grep "path=" | grep Default ' test_expect_success 'stop powerman daemon (setpath2)' ' kill -15 $(cat powermand.pid) && wait ' # # redfishpower plug substitution coverage # test_expect_success 'create powerman.conf for 16 cray redfish nodes (plugsub)' ' cat >powerman_plugsub.conf <<-EOT listen "$testaddr" include "$testdevicesdir/redfishpower-plugsub.dev" device "d0" "redfishpower-plugsub" "$redfishdir/redfishpower -h t[0-15] --test-mode |&" node "t[0-15]" "d0" "Node[0-15]" EOT ' test_expect_success 'start powerman daemon and wait for it to start (plugsub)' ' $powermand -Y -c powerman_plugsub.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_plugsub_query.out && makeoutput "" "t[0-15]" "" >test_plugsub_query.exp && test_cmp test_plugsub_query.exp test_plugsub_query.out ' test_expect_success 'powerman -1 t[0-15] works' ' $powerman -h $testaddr -1 t[0-15] >test_plugsub_on.out && echo Command completed successfully >test_plugsub_on.exp && test_cmp test_plugsub_on.exp test_plugsub_on.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >test_plugsub_query2.out && makeoutput "t[0-15]" "" "" >test_plugsub_query2.exp && test_cmp test_plugsub_query2.exp test_plugsub_query2.out ' test_expect_success 'stop powerman daemon (plugsub)' ' kill -15 $(cat powermand.pid) && wait ' # Note, verbose output can mess up the device script's interpretation of power status, # so restart powermand with verbose mode to run telemetry specific tests. test_expect_success 'create powerman.conf for 16 cray redfish nodes (plugsub2)' ' cat >powerman_plugsub2.conf <<-EOT listen "$testaddr" include "$testdevicesdir/redfishpower-plugsub.dev" device "d0" "redfishpower-plugsub" "$redfishdir/redfishpower -h t[0-15] --test-mode -vv |&" node "t[0-15]" "d0" "Node[0-15]" EOT ' test_expect_success 'start powerman daemon and wait for it to start (plugsub2)' ' $powermand -Y -c powerman_plugsub2.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' # Note: redfishpower-plugsub.dev sets different paths for different # nodes. Following tests check that correct path has been used. test_expect_success 'powerman -T -1 shows correct path being used (t0)' ' $powerman -h $testaddr -T -1 t0 > test_plugsub2_on_T1.out && grep "plugname=Node0" test_plugsub2_on_T1.out | grep "path=" | grep Group0-Node0 ' test_expect_success 'powerman -T -1 shows correct path being used (t8)' ' $powerman -h $testaddr -T -1 t8 > test_plugsub2_on_T2.out && grep "plugname=Node8" test_plugsub2_on_T2.out | grep "path=" | grep Default-Node8 ' test_expect_success 'stop powerman daemon (plugsub2)' ' kill -15 $(cat powermand.pid) && wait ' # # redfishpower plug substitution coverage w/ hypothetical blades # # Blades[0-3] assumed to go through t0 # test_expect_success 'create powerman.conf for 16 cray redfish nodes (plugsubB)' ' cat >powerman_plugsubB.conf <<-EOT listen "$testaddr" include "$testdevicesdir/redfishpower-plugsub-blades.dev" device "d0" "redfishpower-plugsub-blades" "$redfishdir/redfishpower -h t[0-15] --test-mode |&" node "t[0-15]" "d0" "Node[0-15]" node "blade[0-3]" "d0" "Blade[0-3]" EOT ' test_expect_success 'start powerman daemon and wait for it to start (plugsubB)' ' $powermand -Y -c powerman_plugsubB.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_plugsubB_query.out && makeoutput "" "blade[0-3],t[0-15]" "" >test_plugsubB_query.exp && test_cmp test_plugsubB_query.exp test_plugsubB_query.out ' test_expect_success 'powerman -1 blade[0-3],t[0-15] works' ' $powerman -h $testaddr -1 blade[0-3],t[0-15] >test_plugsubB_on.out && echo Command completed successfully >test_plugsubB_on.exp && test_cmp test_plugsubB_on.exp test_plugsubB_on.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >test_plugsubB_query2.out && makeoutput "blade[0-3],t[0-15]" "" "" >test_plugsubB_query2.exp && test_cmp test_plugsubB_query2.exp test_plugsubB_query2.out ' test_expect_success 'stop powerman daemon (plugsubB)' ' kill -15 $(cat powermand.pid) && wait ' # Note, verbose output can mess up the device script's interpretation of power status, # so restart powermand with verbose mode to run telemetry specific tests. test_expect_success 'create powerman.conf for 16 cray redfish nodes (plugsubB2)' ' cat >powerman_plugsubB2.conf <<-EOT listen "$testaddr" include "$testdevicesdir/redfishpower-plugsub-blades.dev" device "d0" "redfishpower-plugsub-blades" "$redfishdir/redfishpower -h t[0-15] --test-mode -vv |&" node "t[0-15]" "d0" "Node[0-15]" node "blade[0-3]" "d0" "Blade[0-3]" EOT ' test_expect_success 'start powerman daemon and wait for it to start (plugsubB2)' ' $powermand -Y -c powerman_plugsubB2.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -T -1 shows correct path being used (t0)' ' $powerman -h $testaddr -T -1 t0 > test_plugsubB2_on_T1.out && grep "plugname=Node0" test_plugsubB2_on_T1.out | grep "path=" | grep Default-Node0 ' test_expect_success 'powerman -T -1 shows correct path being used (t8)' ' $powerman -h $testaddr -T -1 blade0 > test_plugsubB2_on_T2.out && grep "plugname=Blade0" test_plugsubB2_on_T2.out | grep "path=" | grep Default-Blade0 ' test_expect_success 'stop powerman daemon (plugsubB2)' ' kill -15 $(cat powermand.pid) && wait ' # # redfishpower parent coverage (2 levels) # # - t0 is the parent of t[1-15] # test_expect_success 'create powerman.conf for 16 cray redfish nodes (parents2L)' ' cat >powerman_parents2L.conf <<-EOT listen "$testaddr" include "$testdevicesdir/redfishpower-parents-2-levels.dev" device "d0" "redfishpower-parents-2-levels" "$redfishdir/redfishpower -h t[0-15] --test-mode |&" node "t[0-15]" "d0" "Node[0-15]" EOT ' test_expect_success 'start powerman daemon and wait for it to start (parents2L)' ' $powermand -Y -c powerman_parents2L.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_parents2L_query1.out && makeoutput "" "t[0-15]" "" >test_parents2L_query1.exp && test_cmp test_parents2L_query1.exp test_parents2L_query1.out ' # test children can't be turned on if parent off test_expect_success 'powerman -1 t[1-15] completes' ' $powerman -h $testaddr -1 t[1-15] >test_parents2L_on1.out && echo Command completed successfully >test_parents2L_on1.exp && test_cmp test_parents2L_on1.exp test_parents2L_on1.out && $powerman -h $testaddr -T -1 t[1-15] >test_parents2L_on1T.out && grep "cannot perform on, dependency off" test_parents2L_on1T.out ' test_expect_success 'powerman -q shows all off still' ' $powerman -h $testaddr -q >test_parents2L_query2.out && makeoutput "" "t[0-15]" "" >test_parents2L_query2.exp && test_cmp test_parents2L_query2.exp test_parents2L_query2.out ' # test children can be turned on if parent on test_expect_success 'powerman -1 t0 completes' ' $powerman -h $testaddr -1 t0 >test_parents2L_on2.out && echo Command completed successfully >test_parents2L_on2.exp && test_cmp test_parents2L_on2.exp test_parents2L_on2.out ' test_expect_success 'powerman -q shows t0 on' ' $powerman -h $testaddr -q >test_parents2L_query3.out && makeoutput "t0" "t[1-15]" "" >test_parents2L_query3.exp && test_cmp test_parents2L_query3.exp test_parents2L_query3.out ' test_expect_success 'powerman -1 t[1-15] completes' ' $powerman -h $testaddr -1 t[1-15] >test_parents2L_on3.out && echo Command completed successfully >test_parents2L_on3.exp && test_cmp test_parents2L_on3.exp test_parents2L_on3.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >test_parents2L_query4.out && makeoutput "t[0-15]" "" "" >test_parents2L_query4.exp && test_cmp test_parents2L_query4.exp test_parents2L_query4.out ' # turn everything off by group test_expect_success 'powerman -0 t[1-15] completes' ' $powerman -h $testaddr -0 t[1-15] >test_parents2L_off1.out && echo Command completed successfully >test_parents2L_off1.exp && test_cmp test_parents2L_off1.exp test_parents2L_off1.out ' test_expect_success 'powerman -q shows t0 on' ' $powerman -h $testaddr -q >test_parents2L_query5.out && makeoutput "t0" "t[1-15]" "" >test_parents2L_query5.exp && test_cmp test_parents2L_query5.exp test_parents2L_query5.out ' test_expect_success 'powerman -0 t0 completes' ' $powerman -h $testaddr -0 t0 >test_parents2L_off2.out && echo Command completed successfully >test_parents2L_off2.exp && test_cmp test_parents2L_off2.exp test_parents2L_off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_parents2L_query6.out && makeoutput "" "t[0-15]" "" >test_parents2L_query6.exp && test_cmp test_parents2L_query6.exp test_parents2L_query6.out ' # turn off nodes with parent off succeeds test_expect_success 'powerman -0 t[1-15] completes' ' $powerman -h $testaddr -0 t[1-15] >test_parents2L_off3.out && echo Command completed successfully >test_parents2L_off3.exp && test_cmp test_parents2L_off3.exp test_parents2L_off3.out && $powerman -h $testaddr -T -0 t[1-15] >test_parents2L_off3T.out && grep "Node1" test_parents2L_off3T.out | grep "ok" ' # turn on parents & children at same time fails test_expect_success 'powerman -1 t[0-15] completes but doesnt work' ' $powerman -h $testaddr -1 t[0-15] >test_parents2L_on4.out && echo Command completed successfully >test_parents2L_on4.exp && test_cmp test_parents2L_on4.exp test_parents2L_on4.out && $powerman -h $testaddr -T -1 t[0-15] >test_parents2L_on4T.out && grep "cannot turn on parent" test_parents2L_on4T.out ' test_expect_success 'powerman -1 t8,t0 completes but doesnt work' ' $powerman -h $testaddr -1 t[8,0] >test_parents2L_on5.out && echo Command completed successfully >test_parents2L_on5.exp && test_cmp test_parents2L_on5.exp test_parents2L_on5.out && $powerman -h $testaddr -T -1 t[8,0] >test_parents2L_on5T.out && grep "cannot turn on parent" test_parents2L_on5T.out ' # turn on everything test_expect_success 'powerman -0 t0 and then t[1-15] completes' ' $powerman -h $testaddr -1 t0 >test_parents2L_on6.out && echo Command completed successfully >test_parents2L_on6.exp && test_cmp test_parents2L_on6.exp test_parents2L_on6.out && $powerman -h $testaddr -1 t[1-15] >test_parents2L_on6B.out && echo Command completed successfully >test_parents2L_on6B.exp && test_cmp test_parents2L_on6B.exp test_parents2L_on6B.out ' test_expect_success 'powerman -q shows t[0-15] on' ' $powerman -h $testaddr -q >test_parents2L_query7.out && makeoutput "t[0-15]" "" "" >test_parents2L_query7.exp && test_cmp test_parents2L_query7.exp test_parents2L_query7.out ' # turn off everything at same time, dependencies handled test_expect_success 'powerman -0 t[0-15] completes' ' $powerman -h $testaddr -0 t0 >test_parents2L_off3.out && echo Command completed successfully >test_parents2L_off3.exp && test_cmp test_parents2L_off3.exp test_parents2L_off3.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_parents2L_query8.out && makeoutput "" "t[0-15]" "" >test_parents2L_query8.exp && test_cmp test_parents2L_query8.exp test_parents2L_query8.out ' test_expect_success 'stop powerman daemon (parents2L)' ' kill -15 $(cat powermand.pid) && wait ' # # redfishpower parent coverage (3 levels) # # - t0 is the parent of t[1-3] # - t1 is the parent of t[4-7] # - t2 is the parent of t[8-11] # - t3 is the parent of t[12-15] # test_expect_success 'create powerman.conf for 16 cray redfish nodes (parents3L)' ' cat >powerman_parents3L.conf <<-EOT listen "$testaddr" include "$testdevicesdir/redfishpower-parents-3-levels.dev" device "d0" "redfishpower-parents-3-levels" "$redfishdir/redfishpower -h t[0-15] --test-mode |&" node "t[0-15]" "d0" "Node[0-15]" EOT ' test_expect_success 'start powerman daemon and wait for it to start (parents3L)' ' $powermand -Y -c powerman_parents3L.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_parents3L_query1.out && makeoutput "" "t[0-15]" "" >test_parents3L_query1.exp && test_cmp test_parents3L_query1.exp test_parents3L_query1.out ' # test children can't be turned on if parent off test_expect_success 'powerman -1 t[1-3] completes but doesnt work' ' $powerman -h $testaddr -1 t[1-3] >test_parents3L_on1.out && echo Command completed successfully >test_parents3L_on1.exp && test_cmp test_parents3L_on1.exp test_parents3L_on1.out && $powerman -h $testaddr -T -1 t[1-3] >test_parents3L_on1T.out && grep "cannot perform on, dependency off" test_parents3L_on1T.out ' test_expect_success 'powerman -1 t[4-15] completes but doesnt work' ' $powerman -h $testaddr -1 t[4-15] >test_parents3L_on2.out && echo Command completed successfully >test_parents3L_on2.exp && test_cmp test_parents3L_on2.exp test_parents3L_on2.out && $powerman -h $testaddr -T -1 t[4-15] >test_parents3L_on2T.out && grep "cannot perform on, dependency off" test_parents3L_on2T.out ' test_expect_success 'powerman -q shows all off still' ' $powerman -h $testaddr -q >test_parents3L_query2.out && makeoutput "" "t[0-15]" "" >test_parents3L_query2.exp && test_cmp test_parents3L_query2.exp test_parents3L_query2.out ' # test level 2 children can be turned on if parent on test_expect_success 'powerman -1 t0 completes' ' $powerman -h $testaddr -1 t0 >test_parents3L_on3.out && echo Command completed successfully >test_parents3L_on3.exp && test_cmp test_parents3L_on3.exp test_parents3L_on3.out ' test_expect_success 'powerman -q shows t0 on' ' $powerman -h $testaddr -q >test_parents3L_query3.out && makeoutput "t0" "t[1-15]" "" >test_parents3L_query3.exp && test_cmp test_parents3L_query3.exp test_parents3L_query3.out ' test_expect_success 'powerman -1 t1 completes' ' $powerman -h $testaddr -1 t1 >test_parents3L_on4.out && echo Command completed successfully >test_parents3L_on4.exp && test_cmp test_parents3L_on4.exp test_parents3L_on4.out ' test_expect_success 'powerman -q shows t[0-1] on' ' $powerman -h $testaddr -q >test_parents3L_query4.out && makeoutput "t[0-1]" "t[2-15]" "" >test_parents3L_query4.exp && test_cmp test_parents3L_query4.exp test_parents3L_query4.out ' # test level 3 children can be turned on if parents on test_expect_success 'powerman -1 t[4-15] completes' ' $powerman -h $testaddr -1 t[4-15] >test_parents3L_on5.out && echo Command completed successfully >test_parents3L_on5.exp && test_cmp test_parents3L_on5.exp test_parents3L_on5.out ' test_expect_success 'powerman -q shows t[0-1,4-7] on' ' $powerman -h $testaddr -q >test_parents3L_query5.out && makeoutput "t[0-1,4-7]" "t[2-3,8-15]" "" >test_parents3L_query5.exp && test_cmp test_parents3L_query5.exp test_parents3L_query5.out ' # test level 2 & 3 children cannot be turned on together test_expect_success 'powerman -1 t[2-3,8-15] completes but doesnt work' ' $powerman -h $testaddr -1 t[2-3,8-15] >test_parents3L_on6.out && echo Command completed successfully >test_parents3L_on6.exp && test_cmp test_parents3L_on6.exp test_parents3L_on6.out && $powerman -h $testaddr -T -1 t[2-3,8-15] >test_parents3L_on6T.out && grep "cannot turn on parent and child" test_parents3L_on6T.out ' test_expect_success 'powerman -1 t[8-10,2,11-15,3] completes but doesnt work' ' $powerman -h $testaddr -1 t[8-10,2,11-15,3] >test_parents3L_on7.out && echo Command completed successfully >test_parents3L_on7.exp && test_cmp test_parents3L_on7.exp test_parents3L_on7.out && $powerman -h $testaddr -T -1 t[8-10,2,11-15,3] >test_parents3L_on7T.out && grep "cannot turn on parent and child" test_parents3L_on7T.out ' test_expect_success 'powerman -q shows t[0-1,4-7] on' ' $powerman -h $testaddr -q >test_parents3L_query6.out && makeoutput "t[0-1,4-7]" "t[2-3,8-15]" "" >test_parents3L_query6.exp && test_cmp test_parents3L_query6.exp test_parents3L_query6.out ' # turn on t2 test_expect_success 'powerman -1 t2 completes' ' $powerman -h $testaddr -1 t2 >test_parents3L_on8.out && echo Command completed successfully >test_parents3L_on8.exp && test_cmp test_parents3L_on8.exp test_parents3L_on8.out ' test_expect_success 'powerman -q shows t[0-2,4-7] on' ' $powerman -h $testaddr -q >test_parents3L_query7.out && makeoutput "t[0-2,4-7]" "t[3,8-15]" "" >test_parents3L_query7.exp && test_cmp test_parents3L_query7.exp test_parents3L_query7.out ' # turn on level 2 & 3 nodes that are not dependent on each other works test_expect_success 'powerman -1 t[3,8-11] completes' ' $powerman -h $testaddr -1 t[3,8-11] >test_parents3L_on9.out && echo Command completed successfully >test_parents3L_on9.exp && test_cmp test_parents3L_on9.exp test_parents3L_on9.out ' test_expect_success 'powerman -q shows t[0-11] on' ' $powerman -h $testaddr -q >test_parents3L_query8.out && makeoutput "t[0-11]" "t[12-15]" "" >test_parents3L_query8.exp && test_cmp test_parents3L_query8.exp test_parents3L_query8.out ' # turn everything off level 2 nodes, some have children some don't test_expect_success 'powerman -0 t[2-3] completes' ' $powerman -h $testaddr -0 t[2-3] >test_parents3L_off1.out && echo Command completed successfully >test_parents3L_off1.exp && test_cmp test_parents3L_off1.exp test_parents3L_off1.out ' test_expect_success 'powerman -q shows t[0-1,4-7] on' ' $powerman -h $testaddr -q >test_parents3L_query9.out && makeoutput "t[0-1,4-7]" "t[2-3,8-15]" "" >test_parents3L_query9.exp && test_cmp test_parents3L_query9.exp test_parents3L_query9.out ' # turn everything else off test_expect_success 'powerman -0 t0 completes' ' $powerman -h $testaddr -0 t0 >test_parents3L_off2.out && echo Command completed successfully >test_parents3L_off2.exp && test_cmp test_parents3L_off2.exp test_parents3L_off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_parents3L_query10.out && makeoutput "" "t[0-15]" "" >test_parents3L_query10.exp && test_cmp test_parents3L_query10.exp test_parents3L_query10.out ' # turn everything on test_expect_success 'powerman turn on everything' ' $powerman -h $testaddr -1 t0 >test_parents3L_on10A.out && echo Command completed successfully >test_parents3L_on10A.exp && test_cmp test_parents3L_on10A.exp test_parents3L_on10A.out && $powerman -h $testaddr -1 t[1-3] >test_parents3L_on10B.out && echo Command completed successfully >test_parents3L_on10B.exp && test_cmp test_parents3L_on10B.exp test_parents3L_on10B.out && $powerman -h $testaddr -1 t[4-15] >test_parents3L_on10C.out && echo Command completed successfully >test_parents3L_on10C.exp && test_cmp test_parents3L_on10C.exp test_parents3L_on10C.out ' test_expect_success 'powerman -q shows t[0-15] on' ' $powerman -h $testaddr -q >test_parents3L_query11.out && makeoutput "t[0-15]" "" "" >test_parents3L_query11.exp && test_cmp test_parents3L_query11.exp test_parents3L_query11.out ' # turn off everything at same time, dependencies handled test_expect_success 'powerman -0 t[0-15] completes' ' $powerman -h $testaddr -0 t0 >test_parents3L_off3.out && echo Command completed successfully >test_parents3L_off3.exp && test_cmp test_parents3L_off3.exp test_parents3L_off3.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_parents3L_query11.out && makeoutput "" "t[0-15]" "" >test_parents3L_query11.exp && test_cmp test_parents3L_query11.exp test_parents3L_query11.out ' test_expect_success 'stop powerman daemon (parents3L)' ' kill -15 $(cat powermand.pid) && wait ' # # redfishpower parent coverage (3 levels) w/ node that always fails # # - t0 is the parent of t[1-3] # - t1 is the parent of t[4-7] # - t2 is the parent of t[8-11] # - t3 is the parent of t[12-15] # test_expect_success 'create powerman.conf for 16 cray redfish nodes (parents3Lbad)' ' cat >powerman_parents3Lbad.conf <<-EOT listen "$testaddr" include "$testdevicesdir/redfishpower-parents-3-levels.dev" device "d0" "redfishpower-parents-3-levels" "$redfishdir/redfishpower -h t[0-15] --test-mode --test-fail-power-cmd-hosts=t3 |&" node "t[0-15]" "d0" "Node[0-15]" EOT ' test_expect_success 'start powerman daemon and wait for it to start (parents3Lbad)' ' $powermand -Y -c powerman_parents3Lbad.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' # Note, t0 is off, so everything below it is defined as off test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_parents3Lbad_query1.out && makeoutput "" "t[0-15]" "" >test_parents3Lbad_query1.exp && test_cmp test_parents3Lbad_query1.exp test_parents3Lbad_query1.out ' # try turning everything on test_expect_success 'powerman turn on everything' ' $powerman -h $testaddr -1 t0 >test_parents3Lbad_on1A.out && echo Command completed successfully >test_parents3Lbad_on1A.exp && test_cmp test_parents3Lbad_on1A.exp test_parents3Lbad_on1A.out && $powerman -h $testaddr -1 t[1-3] >test_parents3Lbad_on1B.out && echo Command completed successfully >test_parents3Lbad_on1B.exp && test_cmp test_parents3Lbad_on1B.exp test_parents3Lbad_on1B.out && $powerman -h $testaddr -1 t[4-15] >test_parents3Lbad_on1C.out && echo Command completed successfully >test_parents3Lbad_on1C.exp && test_cmp test_parents3Lbad_on1C.exp test_parents3Lbad_on1C.out ' test_expect_success 'powerman -q shows t[0-2,4-11] on, t3 and children unknown' ' $powerman -h $testaddr -q >test_parents3Lbad_query2.out && makeoutput "t[0-2,4-11]" "" "t[3,12-15]" >test_parents3Lbad_query2.exp && test_cmp test_parents3Lbad_query2.exp test_parents3Lbad_query2.out ' # try turning on some children of the bad node test_expect_success 'powerman -1 t[12-15] completes' ' $powerman -h $testaddr -1 t[12-15] >test_parents3Lbad_on2.out && echo Command completed successfully >test_parents3Lbad_on2.exp && test_cmp test_parents3Lbad_on2.exp test_parents3Lbad_on2.out && $powerman -h $testaddr -T -1 t[12-15] >test_parents3Lbad_on2T.out && grep "Node12" test_parents3Lbad_on2T.out | grep "cannot perform on, dependency error" ' test_expect_success 'powerman -q shows t[0-2,4-11] on, t3 and children unknown' ' $powerman -h $testaddr -q >test_parents3Lbad_query3.out && makeoutput "t[0-2,4-11]" "" "t[3,12-15]" >test_parents3Lbad_query3.exp && test_cmp test_parents3Lbad_query3.exp test_parents3Lbad_query3.out ' test_expect_success 'stop powerman daemon (parents3Lbad)' ' kill -15 $(cat powermand.pid) && wait ' # # options # # libcurl specific and not testable under test-mode, so we just check the options work # test_expect_success 'header option setting appears to work' ' echo "quit" | $redfishdir/redfishpower -h t[0-15] --test-mode --header="my content header" 2> header.err grep "header = my content header" header.err ' test_expect_success 'auth option setting appears to work' ' echo "quit" | $redfishdir/redfishpower -h t[0-15] --test-mode --auth="foo:bar" 2> auth.err grep "auth = foo:bar" auth.err ' test_expect_success 'message timeout option setting appears to work' ' echo "quit" | $redfishdir/redfishpower -h t[0-15] --test-mode --message-timeout=33 2> message_timeout.err grep "message timeout = 33" message_timeout.err ' test_expect_success 'resolve-hosts option setting appears to work' ' echo "quit" | $redfishdir/redfishpower -h t[0-15] --test-mode --resolve-hosts 2> resolve_hosts.err grep "resolve-hosts = set" resolve_hosts.err ' # # valgrind # if valgrind --version; then test_set_prereq HAVE_VALGRIND fi # test input largely follows Cray EX chassis test_expect_success HAVE_VALGRIND 'create redfishpower test input' ' cat >redfishpower.in <<-EOT auth USER:PASS setheader Content-Type:application/json setplugs Enclosure 0 setplugs Perif[0-7],Blade[0-7] 0 Enclosure setplugs Node[0-1] [1-2] Blade0 setplugs Node[2-3] [3-4] Blade1 setplugs Node[4-5] [5-6] Blade2 setplugs Node[6-7] [7-8] Blade3 setplugs Node[8-9] [9-10] Blade4 setplugs Node[10-11] [11-12] Blade5 setplugs Node[12-13] [13-14] Blade6 setplugs Node[14-15] [15-16] Blade7 setpath Enclosure,Perif[0-7],Blade[0-7] stat redfish/v1/Chassis/{{plug}} setpath Enclosure,Perif[0-7],Blade[0-7] on redfish/v1/Chassis/{{plug}}/Actions/Chassis.Reset {\"ResetType\":\"On\"} setpath Enclosure,Perif[0-7],Blade[0-7] off redfish/v1/Chassis/{{plug}}/Actions/Chassis.Reset {\"ResetType\":\"ForceOff\"} setpath Node[0-15] stat redfish/v1/Systems/Node0 setpath Node[0-15] on redfish/v1/Systems/Node0/Actions/ComputerSystem.Reset {\"ResetType\":\"On\"} setpath Node[0-15] off redfish/v1/Systems/Node0/Actions/ComputerSystem.Reset {\"ResetType\":\"ForceOff\"} settimeout 60 stat stat Enclosure,Perif[0-7],Blade[0-7],Node[0-15] on Enclosure,Perif[0-7],Blade[0-7],Node[0-15] on Enclosure on Perif[0-7],Blade[0-7] on Node[0-15] stat stat Enclosure,Perif[0-7],Blade[0-7],Node[0-15] off Node[0-15] off Perif[0-7],Blade[0-7] off Enclosure EOT ' test_expect_success HAVE_VALGRIND 'run redfishpower under valgrind' ' cat redfishpower.in | valgrind --tool=memcheck --leak-check=full \ --error-exitcode=1 --gen-suppressions=all \ $redfishdir/redfishpower -h cmm0,t[0-15] --test-mode ' test_done # vi: set ft=sh powerman-2.4.4/t/t0035-power-result.t000077500000000000000000000143201467035776500172510ustar00rootroot00000000000000#!/bin/sh test_description='Test Powerman power result' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman vpcd=$SHARNESS_BUILD_DIRECTORY/t/simulators/vpcd vpcdev=$SHARNESS_TEST_SRCDIR/etc/vpc.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11035 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create test powerman.conf' ' cat >powerman.conf <<-EOT include "$vpcdev" listen "$testaddr" device "test0" "vpc" "$vpcd |&" node "t[0-15]" "test0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query1.out && makeoutput "" "t[0-15]" "" >query1.exp && test_cmp query1.exp query1.out ' # cover "all" script test_expect_success 'powerman -1 t[0-15] works' ' $powerman -h $testaddr -1 t[0-15] >on1.out && echo Command completed successfully >on1.exp && test_cmp on1.exp on1.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query2.out && makeoutput "t[0-15]" "" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman -0 t[0-15] works' ' $powerman -h $testaddr -0 t[0-15] >off1.out && echo Command completed successfully >off1.exp && test_cmp off1.exp off1.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query3.out && makeoutput "" "t[0-15]" "" >query3.exp && test_cmp query3.exp query3.out ' # cover "ranged" script test_expect_success 'powerman -1 t[8-15] works' ' $powerman -h $testaddr -1 t[8-15] >on2.out && echo Command completed successfully >on2.exp && test_cmp on2.exp on2.out ' test_expect_success 'powerman -q shows t[8-15] on' ' $powerman -h $testaddr -q >query4.out && makeoutput "t[8-15]" "t[0-7]" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -0 t[8-15] works' ' $powerman -h $testaddr -0 t[8-15] >off2.out && echo Command completed successfully >off2.exp && test_cmp off2.exp off2.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query5.out && makeoutput "" "t[0-15]" "" >query5.exp && test_cmp query5.exp query5.out ' # cover "singlet" script test_expect_success 'powerman -1 t15 works' ' $powerman -h $testaddr -1 t15 >on3.out && echo Command completed successfully >on3.exp && test_cmp on3.exp on3.out ' test_expect_success 'powerman -q shows t15 on' ' $powerman -h $testaddr -q >query6.out && makeoutput "t15" "t[0-14]" "" >query6.exp && test_cmp query6.exp query6.out ' test_expect_success 'powerman -0 t15 works' ' $powerman -h $testaddr -0 t15 >off3.out && echo Command completed successfully >off3.exp && test_cmp off3.exp off3.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query7.out && makeoutput "" "t[0-15]" "" >query7.exp && test_cmp query7.exp query7.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' # # plug 15 set to bad, so will not work with anything below # test_expect_success 'create test powerman.conf' ' cat >powerman_bad_plug.conf <<-EOT include "$vpcdev" listen "$testaddr" device "test0" "vpc" "$vpcd --bad-plug=15 |&" node "t[0-15]" "test0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman_bad_plug.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'powerman -q shows t[0-14] off' ' $powerman -h $testaddr -q >queryB1.out && makeoutput "" "t[0-14]" "t15" >queryB1.exp && test_cmp queryB1.exp queryB1.out ' # cover "all" script test_expect_success 'powerman -1 t[0-15] fails' ' test_must_fail $powerman -h $testaddr -1 t[0-15] >onB1.out && echo Command completed with errors >onB1.exp && test_cmp onB1.exp onB1.out ' test_expect_success 'powerman -q shows t[0-14] on' ' $powerman -h $testaddr -q >queryB2.out && makeoutput "t[0-14]" "" "t15" >queryB2.exp && test_cmp queryB2.exp queryB2.out ' test_expect_success 'powerman -0 t[0-15] fails' ' test_must_fail $powerman -h $testaddr -0 t[0-15] >offB1.out && echo Command completed with errors >offB1.exp && test_cmp offB1.exp offB1.out ' test_expect_success 'powerman -q shows t[0-14] off' ' $powerman -h $testaddr -q >queryB3.out && makeoutput "" "t[0-14]" "t15" >queryB3.exp && test_cmp queryB3.exp queryB3.out ' # cover "ranged" script test_expect_success 'powerman -1 t[8-15] fails' ' test_must_fail $powerman -h $testaddr -1 t[8-15] >onB2.out && echo Command completed with errors >onB2.exp && test_cmp onB2.exp onB2.out ' test_expect_success 'powerman -q shows t[8-14] on' ' $powerman -h $testaddr -q >queryB4.out && makeoutput "t[8-14]" "t[0-7]" "t15" >queryB4.exp && test_cmp queryB4.exp queryB4.out ' test_expect_success 'powerman -0 t[8-15] fails' ' test_must_fail $powerman -h $testaddr -0 t[8-15] >offB2.out && echo Command completed with errors >offB2.exp && test_cmp offB2.exp offB2.out ' test_expect_success 'powerman -q shows t[0-14] off' ' $powerman -h $testaddr -q >queryB5.out && makeoutput "" "t[0-14]" "t15" >queryB5.exp && test_cmp queryB5.exp queryB5.out ' # cover "singlet" script test_expect_success 'powerman -1 t15 fails' ' test_must_fail $powerman -h $testaddr -1 t15 >onB3.out && echo Command completed with errors >onB3.exp && test_cmp onB3.exp onB3.out ' test_expect_success 'powerman -q shows t[0-14] off' ' $powerman -h $testaddr -q >queryB6.out && makeoutput "" "t[0-14]" "t15" >queryB6.exp && test_cmp queryB6.exp queryB6.out ' test_expect_success 'powerman -0 t15 fails' ' test_must_fail $powerman -h $testaddr -0 t15 >offB3.out && echo Command completed with errors >offB3.exp && test_cmp offB3.exp offB3.out ' test_expect_success 'powerman -q shows t[0-14] off' ' $powerman -h $testaddr -q >queryB7.out && makeoutput "" "t[0-14]" "t15" >queryB7.exp && test_cmp queryB7.exp queryB7.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0036-diagnostics.t000077500000000000000000000126761467035776500171250ustar00rootroot00000000000000#!/bin/sh test_description='Test Powerman diagnostics' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman vpcd=$SHARNESS_BUILD_DIRECTORY/t/simulators/vpcd vpcdev=$SHARNESS_TEST_SRCDIR/etc/vpc.dev # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11036 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } test_expect_success 'create test powerman.conf' ' cat >powerman.conf <<-EOT include "$vpcdev" listen "$testaddr" device "test0" "vpc" "$vpcd |&" node "t[0-15]" "test0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >queryA1.out && makeoutput "" "t[0-15]" "" >queryA1.exp && test_cmp queryA1.exp queryA1.out ' test_expect_success 'powerman -1 t[0-15] works' ' $powerman -h $testaddr -1 t[0-15] >on1.out 2>on1.err && echo Command completed successfully >on1.exp && test_cmp on1.exp on1.out && test_must_be_empty on1.err ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >queryA2.out && makeoutput "t[0-15]" "" "" >queryA2.exp && test_cmp queryA2.exp queryA2.out ' test_expect_success 'powerman -0 t[0-15] works' ' $powerman -h $testaddr -0 t[0-15] >off1.out 2>off1.err && echo Command completed successfully >off1.exp && test_cmp off1.exp off1.out && test_must_be_empty off1.err ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >queryA3.out && makeoutput "" "t[0-15]" "" >queryA3.exp && test_cmp queryA3.exp queryA3.out ' test_expect_success 'powerman -1 t[0-7] works' ' $powerman -h $testaddr -1 t[0-7] >on2.out 2>on2.err && echo Command completed successfully >on2.exp && test_cmp on2.exp on2.out && test_must_be_empty on2.err ' test_expect_success 'powerman -q shows t[0-7] on' ' $powerman -h $testaddr -q >queryA4.out && makeoutput "t[0-7]" "t[8-15]" "" >queryA4.exp && test_cmp queryA4.exp queryA4.out ' test_expect_success 'powerman -0 t[0-7] works' ' $powerman -h $testaddr -0 t[0-7] >off2.out 2>off2.err && echo Command completed successfully >off2.exp && test_cmp off2.exp off2.out && test_must_be_empty off2.err ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >queryA5.out && makeoutput "" "t[0-15]" "" >queryA5.exp && test_cmp queryA5.exp queryA5.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' # # t7,t15 set to bad, so will not work with anything below # test_expect_success 'create test powerman.conf' ' cat >powerman_bad_plug.conf <<-EOT include "$vpcdev" listen "$testaddr" device "test0" "vpc" "$vpcd --bad-plug=7 --bad-plug=15 |&" node "t[0-15]" "test0" EOT ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -c powerman_bad_plug.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -q >/dev/null ' test_expect_success 'powerman -q shows t[0-6,8-14] off, t[7,15] unknown' ' $powerman -h $testaddr -q >queryBP1.out && makeoutput "" "t[0-6,8-14]" "t[7,15]" >queryBP1.exp && test_cmp queryBP1.exp queryBP1.out ' test_expect_success 'powerman -1 t[0-15] fails' ' test_must_fail $powerman -h $testaddr -1 t[0-15] >onBP1.out 2>onBP1.err && echo Command completed with errors >onBP1.exp && test_cmp onBP1.exp onBP1.out && echo t7: ERROR >onBP1.err_exp && echo t15: ERROR >>onBP1.err_exp && test_cmp onBP1.err_exp onBP1.err ' test_expect_success 'powerman -q shows t[0-6,8-14] on, t[7,15] unknown' ' $powerman -h $testaddr -q >queryBP2.out && makeoutput "t[0-6,8-14]" "" "t[7,15]" >>queryBP2.exp && test_cmp queryBP2.exp queryBP2.out ' test_expect_success 'powerman -0 t[0-15] fails' ' test_must_fail $powerman -h $testaddr -0 t[0-15] >offBP1.out 2>offBP1.err && echo Command completed with errors >>offBP1.exp && test_cmp offBP1.exp offBP1.out && echo t7: ERROR >offBP1.err_exp && echo t15: ERROR >>offBP1.err_exp && test_cmp offBP1.err_exp offBP1.err ' test_expect_success 'powerman -q shows t[0-6,8-14] off, t[7,15] unknown' ' $powerman -h $testaddr -q >queryBP3.out && makeoutput "" "t[0-6,8-14]" "t[7,15]" >>queryBP3.exp && test_cmp queryBP3.exp queryBP3.out ' test_expect_success 'powerman -1 t[0-7] fails' ' test_must_fail $powerman -h $testaddr -1 t[0-7] >onBP2.out 2>onBP2.err && echo Command completed with errors >>onBP2.exp && test_cmp onBP2.exp onBP2.out && echo t7: ERROR >onBP2.err_exp && test_cmp onBP2.err_exp onBP2.err ' test_expect_success 'powerman -q shows t[0-6] on' ' $powerman -h $testaddr -q >queryBP4.out && makeoutput "t[0-6]" "t[8-14]" "t[7,15]" >>queryBP4.exp && test_cmp queryBP4.exp queryBP4.out ' test_expect_success 'powerman -0 t[0-7] fails' ' test_must_fail $powerman -h $testaddr -0 t[0-7] >offBP2.out 2>offBP2.err && echo Command completed with errors >>offBP2.exp && test_cmp offBP2.exp offBP2.out && echo t7: ERROR >offBP2.err_exp && test_cmp offBP2.err_exp offBP2.err ' test_expect_success 'powerman -q shows t[0-6,8-14] off, t[7,15] unknown' ' $powerman -h $testaddr -q >queryBP5.out && makeoutput "" "t[0-6,8-14]" "t[7,15]" >>queryBP5.exp && test_cmp queryBP5.exp queryBP5.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0037-cray-ex.t000077500000000000000000000344471467035776500161670ustar00rootroot00000000000000#!/bin/sh test_description='Test Cray EX chassis with redfish' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman redfishdir=$SHARNESS_BUILD_DIRECTORY/src/redfishpower devicesdir=$SHARNESS_TEST_SRCDIR/../etc/devices # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11037 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } # # redfishpower hpe cray supercomputing ex chassis basic test # test_expect_success 'create powerman.conf for chassis w/ 16 redfish nodes (crayex)' ' cat >powerman_cray_ex.conf <<-EOT listen "$testaddr" include "$devicesdir/redfishpower-cray-ex.dev" device "d0" "cray-ex" "$redfishdir/redfishpower -h cmm0,t[0-15] --test-mode |&" node "cmm0,perif[0-7],blade[0-7],t[0-15]" "d0" EOT ' test_expect_success 'start powerman daemon and wait for it to start (crayex)' ' $powermand -Y -c powerman_cray_ex.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_crayex_query1.out && makeoutput "" "blade[0-7],cmm0,perif[0-7],t[0-15]" "" >test_crayex_query1.exp && test_cmp test_crayex_query1.exp test_crayex_query1.out ' # powering on descendants with cmm off, nothing turns on test_expect_success 'powerman -1 blade[0-7] doesnt work' ' test_must_fail $powerman -h $testaddr -1 blade[0-7] >test_crayex_on1.out 2>test_crayex_on1.err && echo Command completed with errors >>test_crayex_on1.exp && test_cmp test_crayex_on1.exp test_crayex_on1.out && count=`grep ^blade test_crayex_on1.err | wc -l` && test $count -eq 8 && count=`grep "cannot perform on, dependency off" test_crayex_on1.err | wc -l` && test $count -eq 8 ' test_expect_success 'powerman -1 perif[0-7] doesnt work' ' test_must_fail $powerman -h $testaddr -1 perif[0-7] >test_crayex_on2.out 2>test_crayex_on2.err && echo Command completed with errors >>test_crayex_on2.exp && test_cmp test_crayex_on2.exp test_crayex_on2.out && count=`grep ^perif test_crayex_on2.err | wc -l` && test $count -eq 8 && count=`grep "cannot perform on, dependency off" test_crayex_on2.err | wc -l` && test $count -eq 8 ' test_expect_success 'powerman -1 t[0-15] doesnt work' ' test_must_fail $powerman -h $testaddr -1 t[0-15] >test_crayex_on3.out 2>test_crayex_on3.err && echo Command completed with errors >>test_crayex_on3.exp && test_cmp test_crayex_on3.exp test_crayex_on3.out && count=`grep ^t test_crayex_on3.err | wc -l` && test $count -eq 16 && count=`grep "cannot perform on, dependency off" test_crayex_on3.err | wc -l` && test $count -eq 16 ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_crayex_query2.out && makeoutput "" "blade[0-7],cmm0,perif[0-7],t[0-15]" "" >test_crayex_query2.exp && test_cmp test_crayex_query2.exp test_crayex_query2.out ' # turn on cmm works test_expect_success 'powerman -1 cmm0 completes' ' $powerman -h $testaddr -1 cmm0 >test_crayex_on4.out && echo Command completed successfully >test_crayex_on4.exp && test_cmp test_crayex_on4.exp test_crayex_on4.out ' test_expect_success 'powerman -q shows cmm0 on' ' $powerman -h $testaddr -q >test_crayex_query3.out && makeoutput "cmm0" "blade[0-7],perif[0-7],t[0-15]" "" >test_crayex_query3.exp && test_cmp test_crayex_query3.exp test_crayex_query3.out ' # turn on children of blades does not work test_expect_success 'powerman -1 t[0-15] doesnt work' ' test_must_fail $powerman -h $testaddr -1 t[0-15] >test_crayex_on5.out 2>test_crayex_on5.err && echo Command completed with errors >>test_crayex_on5.exp && test_cmp test_crayex_on5.exp test_crayex_on5.out && count=`grep ^t test_crayex_on5.err | wc -l` && test $count -eq 16 && count=`grep "cannot perform on, dependency off" test_crayex_on5.err | wc -l` && test $count -eq 16 ' test_expect_success 'powerman -q shows cmm0 on' ' $powerman -h $testaddr -q >test_crayex_query4.out && makeoutput "cmm0" "blade[0-7],perif[0-7],t[0-15]" "" >test_crayex_query4.exp && test_cmp test_crayex_query4.exp test_crayex_query4.out ' # turn on some blades, allows some nodes to be turned on test_expect_success 'powerman -1 blade[4-7] completes' ' $powerman -h $testaddr -1 blade[4-7] >test_crayex_on6.out && echo Command completed successfully >test_crayex_on6.exp && test_cmp test_crayex_on6.exp test_crayex_on6.out ' test_expect_success 'powerman -1 t[0-15] doesnt work, some succeed' ' test_must_fail $powerman -h $testaddr -1 t[0-15] >test_crayex_on7.out 2>test_crayex_on7.err && echo Command completed with errors >>test_crayex_on7.exp && test_cmp test_crayex_on7.exp test_crayex_on7.out && count=`grep ^t test_crayex_on7.err | wc -l` && test $count -eq 8 && count=`grep "cannot perform on, dependency off" test_crayex_on7.err | wc -l` && test $count -eq 8 ' test_expect_success 'powerman -q shows blade[4-7],cmm0,t[8-15] on' ' $powerman -h $testaddr -q >test_crayex_query5.out && makeoutput "blade[4-7],cmm0,t[8-15]" "blade[0-3],perif[0-7],t[0-7]" "" >test_crayex_query5.exp && test_cmp test_crayex_query5.exp test_crayex_query5.out ' # turn on blades and perif and then nodes test_expect_success 'powerman -1 blade[0-3],perif[0-7] completes' ' $powerman -h $testaddr -1 blade[0-3],perif[0-7] >test_crayex_on8.out && echo Command completed successfully >test_crayex_on8.exp && test_cmp test_crayex_on8.exp test_crayex_on8.out ' test_expect_success 'powerman -q shows blade[0-7],cmm0,perif[0-7] on' ' $powerman -h $testaddr -q >test_crayex_query6.out && makeoutput "blade[0-7],cmm0,perif[0-7],t[8-15]" "t[0-7]" "" >test_crayex_query6.exp && test_cmp test_crayex_query6.exp test_crayex_query6.out ' test_expect_success 'powerman -1 t[0-15] completes' ' $powerman -h $testaddr -1 t[0-15] >test_crayex_on6.out && echo Command completed successfully >test_crayex_on6.exp && test_cmp test_crayex_on6.exp test_crayex_on6.out ' test_expect_success 'powerman -q shows blade[0-7],cmm0,t[0-15] on' ' $powerman -h $testaddr -q >test_crayex_query7.out && makeoutput "blade[0-7],cmm0,perif[0-7],t[0-15]" "" "" >test_crayex_query7.exp && test_cmp test_crayex_query7.exp test_crayex_query7.out ' # turn off leaves works test_expect_success 'powerman -0 t[8-15] completes' ' $powerman -h $testaddr -0 t[8-15] >test_crayex_off1.out && echo Command completed successfully >test_crayex_off1.exp && test_cmp test_crayex_off1.exp test_crayex_off1.out ' test_expect_success 'powerman -q shows blade[0-7],cmm0,t[0-7] on' ' $powerman -h $testaddr -q >test_crayex_query8.out && makeoutput "blade[0-7],cmm0,perif[0-7],t[0-7]" "t[8-15]" "" >test_crayex_query8.exp && test_cmp test_crayex_query8.exp test_crayex_query8.out ' # turn off level 2 perif & blades, remaining leaves are now off test_expect_success 'powerman -0 blade[0-7],perif[0-7] completes' ' $powerman -h $testaddr -0 blade[0-7],perif[0-7] >test_crayex_off2.out && echo Command completed successfully >test_crayex_off2.exp && test_cmp test_crayex_off2.exp test_crayex_off2.out ' test_expect_success 'powerman -q shows cmm0 on' ' $powerman -h $testaddr -q >test_crayex_query9.out && makeoutput "cmm0" "blade[0-7],perif[0-7],t[0-15]" "" >test_crayex_query9.exp && test_cmp test_crayex_query9.exp test_crayex_query9.out ' # turn off cmm works test_expect_success 'powerman -0 cmm0 completes' ' $powerman -h $testaddr -0 cmm0 >test_crayex_off3.out && echo Command completed successfully >test_crayex_off3.exp && test_cmp test_crayex_off3.exp test_crayex_off3.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_crayex_query10.out && makeoutput "" "blade[0-7],cmm0,perif[0-7],t[0-15]" "" >test_crayex_query10.exp && test_cmp test_crayex_query10.exp test_crayex_query10.out ' # turn on everything doesn't work # echo blade[0-7],cmm0,perif[0-7],t[0-15]: >test_crayex_on9.exp && test_expect_success 'powerman -1 blade[0-7],cmm0,perif[0-7],t[0-15] doesnt work' ' test_must_fail $powerman -h $testaddr -1 blade[0-7],cmm0,perif[0-7],t[0-15] >test_crayex_on9.out 2>test_crayex_on9.err && echo Command completed with errors >>test_crayex_on9.exp && test_cmp test_crayex_on9.exp test_crayex_on9.out && echo cmm0: cannot turn on parent and child >>test_crayex_on9.err_exp count=`grep ^cmm0 test_crayex_on9.err | wc -l` && test $count -eq 1 && count=`grep ^blade test_crayex_on9.err | wc -l` && test $count -eq 8 && count=`grep ^t test_crayex_on9.err | wc -l` && test $count -eq 16 && count=`grep ^perif test_crayex_on9.err | wc -l` && test $count -eq 8 && count=`grep "cannot turn on parent and child" test_crayex_on9.err | wc -l` && test $count -eq 33 ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_crayex_query11.out && makeoutput "" "blade[0-7],cmm0,perif[0-7],t[0-15]" "" >test_crayex_query11.exp && test_cmp test_crayex_query11.exp test_crayex_query11.out ' # turn everything on test_expect_success 'powerman turn on everything' ' $powerman -h $testaddr -1 cmm0 >test_crayex_on9A.out && echo Command completed successfully >test_crayex_on9A.exp && test_cmp test_crayex_on9A.exp test_crayex_on9A.out && $powerman -h $testaddr -1 blade[0-7],perif[0-7] >test_crayex_on9B.out && echo Command completed successfully >test_crayex_on9B.exp && test_cmp test_crayex_on9B.exp test_crayex_on9B.out && $powerman -h $testaddr -1 t[0-15] >test_crayex_on9C.out && echo Command completed successfully >test_crayex_on9C.exp && test_cmp test_crayex_on9C.exp test_crayex_on9C.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >test_crayex_query12.out && makeoutput "blade[0-7],cmm0,perif[0-7],t[0-15]" "" "" >test_crayex_query12.exp && test_cmp test_crayex_query12.exp test_crayex_query12.out ' # turn off everything works test_expect_success 'powerman -0 blade[0-3],cmm0,perif[0-7],t[0-15] completes' ' $powerman -h $testaddr -0 blade[0-3],cmm0,perif[0-7],t[0-15] >test_crayex_off4.out && echo Command completed successfully >test_crayex_off4.exp && test_cmp test_crayex_off4.exp test_crayex_off4.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_crayex_query13.out && makeoutput "" "blade[0-7],cmm0,perif[0-7],t[0-15]" "" >test_crayex_query13.exp && test_cmp test_crayex_query13.exp test_crayex_query13.out ' test_expect_success 'stop powerman daemon (crayex)' ' kill -15 $(cat powermand.pid) && wait ' # # redfishpower hpe cray supercomputing ex chassis test - some unpopulated # # assume perif[4-7] and blade[4-7] do not exist # as a result t[8-15] do not exist # test_expect_success 'create powerman.conf for chassis w/ 16 redfish nodes (crayexU)' ' cat >powerman_cray_ex_U.conf <<-EOT listen "$testaddr" include "$devicesdir/redfishpower-cray-ex.dev" device "d0" "cray-ex" "$redfishdir/redfishpower -h cmm0,t[0-7],unused[0-7] --test-mode |&" node "cmm0,perif[0-3],blade[0-3],t[0-7]" "d0" "Enclosure,Perif[0-3],Blade[0-3],Node[0-7]" EOT ' test_expect_success 'start powerman daemon and wait for it to start (crayexU)' ' $powermand -Y -c powerman_cray_ex_U.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_crayexU_query1.out && makeoutput "" "blade[0-3],cmm0,perif[0-3],t[0-7]" "" >test_crayexU_query1.exp && test_cmp test_crayexU_query1.exp test_crayexU_query1.out ' # turn on undefined stuff leads to errors test_expect_success 'powerman fails on unpopulated targets' ' test_must_fail $powerman -h $testaddr -1 blade4 && test_must_fail $powerman -h $testaddr -1 perif5 && test_must_fail $powerman -h $testaddr -1 t8 ' # turn on everything works test_expect_success 'powerman turn on everything' ' $powerman -h $testaddr -1 cmm0 >test_crayexU_on9A.out && echo Command completed successfully >test_crayexU_on9A.exp && test_cmp test_crayexU_on9A.exp test_crayexU_on9A.out && $powerman -h $testaddr -1 blade[0-3],perif[0-3] >test_crayexU_on9B.out && echo Command completed successfully >test_crayexU_on9B.exp && test_cmp test_crayexU_on9B.exp test_crayexU_on9B.out && $powerman -h $testaddr -1 t[0-7] >test_crayexU_on9C.out && echo Command completed successfully >test_crayexU_on9C.exp && test_cmp test_crayexU_on9C.exp test_crayexU_on9C.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >test_crayexU_query2.out && makeoutput "blade[0-3],cmm0,perif[0-3],t[0-7]" "" "" >test_crayexU_query2.exp && test_cmp test_crayexU_query2.exp test_crayexU_query2.out ' # turn off everything works test_expect_success 'powerman -0 blade[0-3],cmm0,perif[0-3],t[0-7] completes' ' $powerman -h $testaddr -0 blade[0-3],cmm0,perif[0-3],t[0-7] >test_crayexU_off1.out && echo Command completed successfully >test_crayexU_off1.exp && test_cmp test_crayexU_off1.exp test_crayexU_off1.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_crayexU_query3.out && makeoutput "" "blade[0-3],cmm0,perif[0-3],t[0-7]" "" >test_crayexU_query3.exp && test_cmp test_crayexU_query3.exp test_crayexU_query3.out ' test_expect_success 'stop powerman daemon (crayexU)' ' kill -15 $(cat powermand.pid) && wait ' # # redfishpower hpe cray supercomputing ex chassis test - parent failure # see issue #197 # test_expect_success 'create powerman.conf for chassis w/ 16 redfish nodes (crayexfail)' ' cat >powerman_cray_ex_fail.conf <<-EOT listen "$testaddr" include "$devicesdir/redfishpower-cray-ex.dev" device "d0" "cray-ex" "$redfishdir/redfishpower -h cmm0,t[0-15] --test-mode --test-fail-power-cmd-hosts=cmm0 |&" node "cmm0,perif[0-7],blade[0-7],t[0-15]" "d0" EOT ' test_expect_success 'start powerman daemon and wait for it to start (crayexfail)' ' $powermand -Y -c powerman_cray_ex_fail.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all unknown' ' $powerman -h $testaddr -q >test_crayexfail_query1.out && makeoutput "" "" "blade[0-7],cmm0,perif[0-7],t[0-15]" >test_crayexfail_query1.exp && test_cmp test_crayexfail_query1.exp test_crayexfail_query1.out ' test_expect_success 'powerman -1 t0 dependency error (parent error)' ' test_must_fail $powerman -h $testaddr -1 t0 >test_crayexfail_on1.out 2>test_crayexfail_on1.err && grep "cannot perform on, dependency error" test_crayexfail_on1.err ' test_expect_success 'stop powerman daemon (crayexfail)' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0038-cray-ex-rabbit.t000077500000000000000000000144071467035776500174230ustar00rootroot00000000000000#!/bin/sh test_description='Test Cray EX chassis with redfish' . `dirname $0`/sharness.sh powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman redfishdir=$SHARNESS_BUILD_DIRECTORY/src/redfishpower devicesdir=$SHARNESS_TEST_SRCDIR/../etc/devices # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11038 makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } # # redfishpower hpe cray supercomputing ex chassis test - rabbit # # note rabbit blade is descendant of perif 7 # test_expect_success 'create powerman.conf for chassis w/ 16 redfish nodes and rabbit (crayexR)' ' cat >powerman_cray_ex_R.conf <<-EOT listen "$testaddr" include "$devicesdir/redfishpower-cray-ex-rabbit.dev" device "d0" "cray-ex-rabbit" "$redfishdir/redfishpower -h cmm0,t[0-15],rabbit --test-mode |&" node "cmm0,perif[0-4,7],blade[0-7],t[0-15],rabbit" "d0" "Enclosure,Perif[0-4,7],Blade[0-7],Node[0-16]" EOT ' test_expect_success 'start powerman daemon and wait for it to start (crayexR)' ' $powermand -Y -c powerman_cray_ex_R.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_crayexR_query1.out && makeoutput "" "blade[0-7],cmm0,perif[0-4,7],rabbit,t[0-15]" "" >test_crayexR_query1.exp && test_cmp test_crayexR_query1.exp test_crayexR_query1.out ' # powering on rabbit with cmm and perif7 off test_expect_success 'powerman -1 rabbit doesnt work' ' test_must_fail $powerman -h $testaddr -1 rabbit >test_crayexR_on1.out 2>test_crayexR_on1.err && echo Command completed with errors >>test_crayexR_on1.exp && test_cmp test_crayexR_on1.exp test_crayexR_on1.out && grep "rabbit: cannot perform on, dependency off" test_crayexR_on1.err ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_crayexR_query2.out && makeoutput "" "blade[0-7],cmm0,perif[0-4,7],rabbit,t[0-15]" "" >test_crayexR_query2.exp && test_cmp test_crayexR_query2.exp test_crayexR_query2.out ' # turn on cmm works, can't turn on rabbit test_expect_success 'powerman -1 cmm0 completes' ' $powerman -h $testaddr -1 cmm0 >test_crayexR_on2.out && echo Command completed successfully >test_crayexR_on2.exp && test_cmp test_crayexR_on2.exp test_crayexR_on2.out ' test_expect_success 'powerman -1 rabbit doesnt work' ' test_must_fail $powerman -h $testaddr -1 rabbit >test_crayexR_on3.out 2>test_crayexR_on3.err && echo Command completed with errors >>test_crayexR_on3.exp && test_cmp test_crayexR_on3.exp test_crayexR_on3.out && grep "rabbit: cannot perform on, dependency off" test_crayexR_on3.err ' test_expect_success 'powerman -q shows cmm0 on' ' $powerman -h $testaddr -q >test_crayexR_query3.out && makeoutput "cmm0" "blade[0-7],perif[0-4,7],rabbit,t[0-15]" "" >test_crayexR_query3.exp && test_cmp test_crayexR_query3.exp test_crayexR_query3.out ' # turn on perif7 works, can turn on rabbit now test_expect_success 'powerman -1 perif7 completes' ' $powerman -h $testaddr -1 perif7 >test_crayexR_on4.out && echo Command completed successfully >test_crayexR_on4.exp && test_cmp test_crayexR_on4.exp test_crayexR_on4.out ' test_expect_success 'powerman -1 rabbit completes' ' $powerman -h $testaddr -1 rabbit >test_crayexR_on5.out && echo Command completed successfully >test_crayexR_on5.exp && test_cmp test_crayexR_on5.exp test_crayexR_on5.out ' test_expect_success 'powerman -q shows cmm0,perif7,rabbit on' ' $powerman -h $testaddr -q >test_crayexR_query4.out && makeoutput "cmm0,perif7,rabbit" "blade[0-7],perif[0-4],t[0-15]" "" >test_crayexR_query4.exp && test_cmp test_crayexR_query4.exp test_crayexR_query4.out ' # turn off rabbit, perif7, cmm0 test_expect_success 'powerman -0 rabbit completes' ' $powerman -h $testaddr -0 rabbit >test_crayexR_off1.out && echo Command completed successfully >test_crayexR_off1.exp && test_cmp test_crayexR_off1.exp test_crayexR_off1.out ' test_expect_success 'powerman -0 perif7 completes' ' $powerman -h $testaddr -0 perif7 >test_crayexR_off2.out && echo Command completed successfully >test_crayexR_off2.exp && test_cmp test_crayexR_off2.exp test_crayexR_off2.out ' test_expect_success 'powerman -0 cmm0 completes' ' $powerman -h $testaddr -0 cmm0 >test_crayexR_off3.out && echo Command completed successfully >test_crayexR_off3.exp && test_cmp test_crayexR_off3.exp test_crayexR_off3.out ' test_expect_success 'powerman -q shows everything off' ' $powerman -h $testaddr -q >test_crayexR_query5.out && makeoutput "" "blade[0-7],cmm0,perif[0-4,7],rabbit,t[0-15]" "" >test_crayexR_query5.exp && test_cmp test_crayexR_query5.exp test_crayexR_query5.out ' # turn on everything test_expect_success 'powerman turn on everything' ' $powerman -h $testaddr -1 cmm0 >test_crayexR_on6A.out && echo Command completed successfully >test_crayexR_on6A.exp && test_cmp test_crayexR_on6A.exp test_crayexR_on6A.out && $powerman -h $testaddr -1 blade[0-7],perif[0-4,7] >test_crayexR_on6B.out && echo Command completed successfully >test_crayexR_on6B.exp && test_cmp test_crayexR_on6B.exp test_crayexR_on6B.out && $powerman -h $testaddr -1 t[0-15],rabbit >test_crayexR_on6C.out && echo Command completed successfully >test_crayexR_on6C.exp && test_cmp test_crayexR_on6C.exp test_crayexR_on6C.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >test_crayexR_query6.out && makeoutput "blade[0-7],cmm0,perif[0-4,7],rabbit,t[0-15]" "" "" >test_crayexR_query6.exp && test_cmp test_crayexR_query6.exp test_crayexR_query6.out ' # turn off everything works test_expect_success 'powerman -0 blade[0-7],cmm0,perif[0-4,7],rabbit,t[0-15] completes' ' $powerman -h $testaddr -0 blade[0-7],cmm0,perif[0-4,7],rabbit,t[0-15] >test_crayexR_off4.out && echo Command completed successfully >test_crayexR_off4.exp && test_cmp test_crayexR_off4.exp test_crayexR_off4.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >test_crayexR_query7.out && makeoutput "" "blade[0-7],cmm0,perif[0-4,7],rabbit,t[0-15]" "" >test_crayexR_query7.exp && test_cmp test_crayexR_query7.exp test_crayexR_query7.out ' test_expect_success 'stop powerman daemon (crayexR)' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh powerman-2.4.4/t/t0039-llnl-el-capitan-cluster.t000077500000000000000000000067661467035776500212570ustar00rootroot00000000000000#!/bin/sh test_description='Check LLNL El Capitan config' . `dirname $0`/sharness.sh ulimit -n 2048 powermand=$SHARNESS_BUILD_DIRECTORY/src/powerman/powermand powerman=$SHARNESS_BUILD_DIRECTORY/src/powerman/powerman redfishpower=$SHARNESS_BUILD_DIRECTORY/src/redfishpower/redfishpower devicesdir=$SHARNESS_TEST_SRCDIR/../etc/devices # Use port = 11000 + test number # That way there won't be port conflicts with make -j testaddr=localhost:11039 echo "Command completed successfully" >success.exp is_successful() { test_cmp success.exp $1 } makeoutput() { printf "on: %s\n" $1 printf "off: %s\n" $2 printf "unknown: %s\n" $3 } # Usage: gendevices chassis_count gendevices() { for i in $(seq 0 $(($1-1))); do lo=$(($i*16)) hi=$((${lo}+15)) echo "device \"cmm$i\" \"cray-ex\" \"$redfishpower --test-mode -h elcap-cmm$i,pelcap[$lo-$hi] |&\"" done } # Usage: gennodes chassis_count gennodes() { for i in $(seq 0 $(($1-1))); do lo=$(($i*8)) hi=$((${lo}+7)) nlo=$(($i*16)) nhi=$((${nlo}+15)) echo "node \"elcap-cmm$i,elcap-perif[$lo-$hi],elcap-blade[$lo-$hi],elcap[$nlo-$nhi]\" \"cmm$i\"" done } # This is just a placeholder until we get the config of the real # HPE Cray EX Shasta system test_expect_success 'create powerman.conf for El Cap' ' (echo "listen \"$testaddr\""; \ echo "include \"$devicesdir/redfishpower-cray-ex.dev\""; \ gendevices 1024; \ gennodes 1024) >powerman.conf ' test_expect_success 'start powerman daemon and wait for it to start' ' $powermand -Y -c powerman.conf & echo $! >powermand.pid && $powerman --retry-connect=100 --server-host=$testaddr -d >device.out ' CMMSTR="elcap-cmm[0-1023]" BLADESTR="elcap-blade[0-8191]" PERIFSTR="elcap-perif[0-8191]" NODESTR="elcap[0-16383]" ALLSTR="$NODESTR,$BLADESTR,$CMMSTR,$PERIFSTR" test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query.out && makeoutput "" "$ALLSTR" "" >query.exp && test_cmp query.exp query.out ' test_expect_success 'powerman can turn on Enlcosures' ' $powerman -h $testaddr -1 $CMMSTR >on.out && is_successful on.out ' test_expect_success 'powerman -q shows Enclosures on' ' $powerman -h $testaddr -q >query2.out && makeoutput "$CMMSTR" "$NODESTR,$BLADESTR,$PERIFSTR" "" >query2.exp && test_cmp query2.exp query2.out ' test_expect_success 'powerman can turn on Blades + Perifs' ' $powerman -h $testaddr -1 $BLADESTR,$PERIFSTR >on2.out && is_successful on2.out ' test_expect_success 'powerman -q shows Enclosures + Blades + Perifs on' ' $powerman -h $testaddr -q >query3.out && makeoutput "$BLADESTR,$CMMSTR,$PERIFSTR" "$NODESTR" >query3.exp && test_cmp query3.exp query3.out ' test_expect_success 'powerman can turn on Nodes' ' $powerman -h $testaddr -1 $NODESTR >on3.out && is_successful on3.out ' test_expect_success 'powerman -q shows all on' ' $powerman -h $testaddr -q >query4.out && makeoutput "$ALLSTR" "" "" >query4.exp && test_cmp query4.exp query4.out ' test_expect_success 'powerman -0 all works' ' $powerman -h $testaddr -0 $ALLSTR >off.out && is_successful off.out ' test_expect_success 'powerman -q shows all off' ' $powerman -h $testaddr -q >query5.out && makeoutput "" "$ALLSTR" "" >query5.exp && test_cmp query5.exp query5.out ' test_expect_success 'powerman -q works with giant input' ' nodes=$(echo elcap\[$(seq -s, 0 2 16382)\]) && $powerman -h $testaddr -q $nodes >query6.out && makeoutput "" "$nodes" "" >query6.exp && test_cmp query6.exp query6.out ' test_expect_success 'stop powerman daemon' ' kill -15 $(cat powermand.pid) && wait ' test_done # vi: set ft=sh