diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d60c31a --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + 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. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..bb4acee --- /dev/null +++ b/INSTALL @@ -0,0 +1,60 @@ +Makefile +======== +Since this program is not portable at all, there is no configure script and +no options. + +Edit Makefile and specify the path to your C-compiler! +Common values are +CC=/usr/vac/bin/xlc +or +CC=gcc + +Compile with +$ make + +When you see compiler errors, check the compiler version! + +Copy the binaries to your Nagios libexec directory (e.g. /usr/local/nagios/libexec) +The binaries do not need root permission, all run fine with any unprivileged user. + +Binaries +======== +The included binaries were built on AIX 5.3 TL12 with xlC 8.0.0.26 and were tested +on AIX 5.3 TL12, AIX 6.1 and AIX 7.1. They are included for convenience, but there +is no guarantee that they work on all AIX systems. +To compile own binaries please do a "make clean; make"! + +Tested compilers +================ +IBM xlC 8.0 or newer + bos.adt.base and bos.adt.include are dependencies of the compiler + +gcc 4.8.2 (from perzl.org) was tested on AIX 5.3 TL12, 6.1 TL7 and 7.1 TL2. + Older gcc versions probably work too. + Make sure to install an OS-compatible gcc version! + If you see compiler errors in system header files (like /usr/include/secattr.h), + then you probably installed the wrong gcc version (e.g. gcc for AIX 5.3 on AIX 6.1) + It might be necessary to install the system header files from the filesets + bos.adt.base and bos.adt.include! + +Operating systems +================= +The monitors will compile and run on AIX 5.3 TL6 or higher, AIX 6.1 and AIX 7.1 +The perfstat pool API is not present in earlier versions and there are also hardware +dependencies (see below). + +Hardware +======== +The monitor can be compiled on any AIX hardware which runs a supported AIX version. +It might be possible, that the monitor won't run because of PowerVM restrictions +or LPAR settings. See README for details + +The monitor will run on Power5 or newer CPUs (tested on Power6 and 7). + +2 types of LPARs are supported: +- shared processor LPAR +- dedicated donating LPAR (only entitlement monitors) + +It is not possible to monitor dedicated or full partition LPARs with this monitor +because it's no entitlement or pool data available there from the perfstat API. + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5a31ca8 --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +# Makefile for check_ent_pools and friends +# +# gcc tested working on AIX>5.3 TL12 SP5, need to make sure to run the gcc for the +# correct AIX version (gcc for AIX 5.3 will NOT work on AIX 6.1 and stop +# with errors in various system include files) +# +#CC=gcc +# +CC=/usr/vac/bin/xlc + +LIBS=-lperfstat + +all: check_ent_pools check_entitlement check_cpu_pools + +check_ent_pools: check_ent_pools.c + $(CC) $(LIBS) check_ent_pools.c -o $@ + +check_entitlement: check_entitlement.c + $(CC) $(LIBS) check_entitlement.c -o $@ + +check_cpu_pools: check_cpu_pools.c + $(CC) $(LIBS) check_cpu_pools.c -o $@ + +clean: + rm -f check_ent_pools check_entitlement check_cpu_pools diff --git a/README b/README new file mode 100644 index 0000000..47be9e6 --- /dev/null +++ b/README @@ -0,0 +1,187 @@ +check_ent_pools is a combined monitor for entitlement and pool monitoring +check_entitlement monitors just entitlement usage +check_pools monitors just pool usage + +See INSTALL on how to compile and install the set of monitors! +See command line option --help for details about all options! + +LPAR prerequisites +================== + +The monitor runs on Power5/6/7 hardware with shared processor LPARs or +dedicated donating LPARs. + +$ lparstat -i|grep -E "Type|Mode" + +will show values like Shared-SMT, Shared, Shared-SMT-4 or Donating, Donating-SMT.. +When running a donating LPAR, "Mode" will show "donating" + +To be able to monitor pool data, the option "Enable performance collection" in +the LPAR profile must be set! + +It is always useful to check if nmon (option p) shows sane entitlement and pool data! +There were bugs in certain AIX levels resulting in wrong or even no performance data at all. + + +Monitoring LPAR entitlement and vCPU usage +========================================== + +These monitors are avaliable in check_ent_pools and check_entitlement and work on shared and +dedicated donating LPARs. + +-ew and -ec monitor the consumed entitlement over the check interval. +Valid values are absolute values or percentage values, you can specify even both at the same time: +e.g. -ec 3.5 -ec 200% will set thresholds to 3.5 CPUs _and_ whatever 200% of the LPAR entitlement is. +Percentage values apply to the configured entitlement value of the LPAR. +Percentage values range from 1% to 2000% representing the minimum entitlment of 0.05 +for a LPAR with 1 vCPU. +Absolute values are positive floating point numbers with 1 decimal place. + +The monitor does not enforce values that match the possible maximum! That means the threshold can be +set to 6 even though the LPAR has only 3 vCPUs, or to 2000% on a 1.0 entitlement LPAR with 2 vCPUs. +I don't consider this a bug :-) Convince me when you think it is one! + +Warning (-ew) and critical (-ec) options can be placed independently, e.g. it's possible to create only +critical events but no warnings. + +-vbw and -vbc monitor the number of virtual CPUs busy and take only percentage values (1..100%). +-vbc 95% will generate critical events, when the entitlement usage of the LPAR is higher than 95% +of the configured number of vCPUs. + + +Monitoring shared cpu pools +=========================== + +These monitors are avaliable in check_ent_pools and check_cpu_pools and work on shared LPARs only. +"Enable performance collection" needs to be enabled on the HMC. + +The monitors will measure usage of the shared CPU pool the LPARs is a member of. +Pool usage of different CPU pools can not be monitored on one LPAR! + +$ lparstat -i|grep "Shared Pool ID" + +will show the monitored CPU pool. + +-pw and -pc monitor the entitlement consumption of the current CPU pool the monitor runs on. +Thresholds can be absolute values representing entitlement consumption or percentage values +representing relative consumption applied to the pool size. +Absolute values and percentage values can be used at the same time: e.g. -pw 10 -pw 90% + +Attention: The size of pool 0 is always equal to the number of available CPUs for all available +shared CPU pools, but the utilization data includes only pool 0 LPARs! Be careful to monitor +pool 0 LPARs, especially when there are other CPU pools! +To monitor the managed system utilization, DO NOT monitor pool 0, use the system pool monitor! +The size of pool 0 is "variable" when dedicated donating LPARs are used. + +-pfw and -pfc are used to monitor for free capacity. -pfc 2 will generate critical events when the +CPU pool has less than 2 CPUs free. Same applies to percentage values, you can have both at the +same time. + +Maximum hardware limits are not enforced for thresholds. + + +Monitoring the global or system pool +==================================== + +These monitors are avaliable in check_ent_pools and check_cpu_pools and work on shared LPARs only. +"Enable performance collection" needs to be enabled on the HMC. + +The monitors will measure the utilization of the whole managed system (global or system pool), +including all the various CPU pools and the hypervisor. + +$ lparstat -i|grep "Shared Physical CPUs in system" + +will show the number of CPUs in the system pool. + +-sw and -sc monitor the entitlement consumption of the system pool. +Thresholds are absolute values representing the entitlement consumption of the managed system or +percentage values representing relative consumption of all available CPUs. +Both absolute and percentage values can be used at the same time. + +-sfw and -sfc monitor the free capacity in the system pool. +Use absolute and/or percentage values to check the amount of free entitlement in the managed system. + +Maximum hardware limits are not enforced for thresholds. + +From experience, the hypervisor uses up to 1.0 entitlement on a p770, maybe more on larger machines, +maybe less on smaller machines. +Take this in mind when setting thresholds to close to the maximum hardware limit! Alarming may be +to late... + +The consumption of dedicated LPARs is invisible to this monitor. Dedicated LPARs simply reduce the +amount of available pool CPUs. + +Important: Dedicated donating LPARs dynamically reduce the size of the system pool. This might lead +to confusion, espescially when relative percentages are used for monitoring. + + +Check interval +============== + +Performace values are calculated as average over a certain period of time. +Default interval is 1 second, maximum is 30 seconds. +Be careful with high values, you may need to adjust the nagios plugin timeout! + + +Strict checking +=============== + +Sometimes IBM manages to screw things like firmware, kernel or performance library. +Check e.g. IV33883 for details. +When this happens, most of the thresholds are never reached. You'll never notice such situation +because you never get any warning or critical events. +If you're nevertheless interested in getting a notification, use strict checking +(--strict or -x) to receive a critical event. + +The current checked values are: +- entitlement usage = 0 +- LPAR entitlement = 0 +- Size of current CPU pool = 0 +- Busy time of current CPU pool = 0 +- Number of CPUs in managed system = 0 +- Usage of CPUs in managed system = 0 +- Number of current pool CPUs > number of CPUs in managed system + +More checks will be implemented as the need arises. + + +Monitor Output +============== + +Because of the high number of thresholds, the output is quite large. +Matching thresholds are printed behind the metric in parentheses. Possible values are OK, WARNING, +CRITICAL. Unused or unmonitored thresholds always evaluate to "OK". +Additional data is included to show the complete picture of the machine state. +Performance data is also printed with all the additional values. + +Example for check_ent_pools: + +ENT_POOLS OK ent_used=0.43(OK) ent=0.50 ent_max=2 vcpu_busy=21.45%(OK) pool_id=11 pool_size=9 \ +pool_used=1.28(OK) pool_free=7.71(OK) syspool_size=16 syspool_used=3.47(OK) syspool_free=12.53(OK) \ +|ent_used=0.43;ent=0.50;ent_max=2;vcpu_busy=21.45;pool_id=11;pool_size=9;pool_used=1.28;pool_free=7.71;\ +syspool_size=16;syspool_used=3.47;syspool_free=12.53 + +ent_used : used entitlement of the LPAR +ent : Entitled capacity of LPAR (lparstat -i|grep "Entitled Capacity" ) +ent_max : maximum usable entitlement, same as numer of vCPUs +vcpu_busy : percentage of all consumend vCPU (ent/max_ent*100) +pool_id : shared cpu pool id of this LPAR (lparstat -i|grep "Shared Pool ID") +pool_size : size of the shared cpu pool "pool_id" (lparstat -i|grep "Active CPUs in Pool") +pool_used : used entitlement of the pool "pool_id" +pool_free : free entitlement in the pool "pool_id" +syspool_size : size of the system cpu pool (lparstat -i|grep "Shared Physical CPUs in system") +syspool_used : used entitlement of the system shared cpu pool +syspool_free : free entitlement in the system shared cpu pool + + +Thanks +====== + +Thanks go to Michael Perzl for supplying me with a working getopt_long for AIX and all the people from +the AIX Developer Works forums for answering my stupid questions. + + +Bugs +==== +None known at the moment. + diff --git a/check_cpu_pools.c b/check_cpu_pools.c new file mode 100644 index 0000000..a84a3e1 --- /dev/null +++ b/check_cpu_pools.c @@ -0,0 +1,973 @@ +/* + * monitors pool usage (system and other shared pools) on shared processor LPARs + * not usable on dedicated LPARs + * compiles with IBM xlC and gcc on AIX 5.3(>TL6), 6.1 and 7.1 + * + * Compile with: cc -o check_cpu_pools -lperfstat check_cpu_pools.c + * + * This is stripped down from check_ent_pools.c, entitlement parts removed + * + * This nagios plugin comes with ABSOLUTELY NO WARRANTY. You may redistribute + * copies of the plugin under the terms of the GNU General Public License. + * For more information about these matters, see the file named COPYING. +*/ +const char *progname = "check_cpu_pools"; +const char *program_name = "check_cpu_pools"; +const char *copyright = "2014"; +const char *email = "armink.nagios@gmail.com"; +const char *name = "Armin K"; +const char *version = "1.2"; + +#include +#include +#include +#include +#include +#include +#include + +#ifndef XINTFRAC /* for timebase calculations... */ +#include /* only necessary in AIX 5.3, AIX >=6.1 defines this in libperfstat.h */ +#define XINTFRAC ((double)(_system_configuration.Xint)/(double)(_system_configuration.Xfrac)) +#endif + +/* include GNU getopt_long, since AIX does not provide it */ +#include "getopt_long.h" +#include "getopt_long.c" + +/* define Nagios return codes */ +enum { + STATE_OK, + STATE_WARNING, + STATE_CRITICAL, + STATE_UNKNOWN, + STATE_DEPENDENT +}; + +/* string representations of the return codes */ +char *states[5]={"OK","WARNING","CRITICAL","UNKNOWN","DEPENDENT"}; + +/* initial state values */ +int ent_pool_state=STATE_OK, temp_state=STATE_OK; +int ent_state=STATE_OK; +int pool_state=STATE_OK, pool_free_state=STATE_OK; +int syspool_state=STATE_OK, syspool_free_state=STATE_OK; + +int dedicated_donating=0; /* marker for dedicated donating mode */ +int interval=1; /* default interval in seconds between the 2 perflib calls = monitoring period */ +int verbose=FALSE; /* only 1 verbose level... violating the plugin recommendations here */ +int strict=FALSE; /* additional sanity checking of various system values */ +int pool_check_requested=0; /* indicator for pool check requests, to react properly when there are no pools to check */ + +/* monitoring variables */ +double pool_critical_pct=0, pool_warning_pct=0; +double pool_critical=0, pool_warning=0; +double pool_free_critical_pct=0, pool_free_warning_pct=0; +double pool_free_critical=0, pool_free_warning=0; +double system_critical_pct=0, system_warning_pct=0; +double system_critical=0, system_warning=0; +double system_free_critical_pct=0, system_free_warning_pct=0; +double system_free_critical=0, system_free_warning=0; + + +/* helper functions "stolen" from util.c and utilbase.c */ +int is_numeric (char *number) +{ + char tmp[1]; + float x; + + if (!number) + return FALSE; + else if (sscanf (number, "%f%c", &x, tmp) == 1) + return TRUE; + else + return FALSE; +} + +int is_positive (char *number) +{ + if (is_numeric (number) && atof (number) > 0.0) + return TRUE; + else + return FALSE; +} + + +int is_percentage (char *number) +{ + int x; + if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100) + return TRUE; + else + return FALSE; +} + +int is_integer (char *number) +{ + long int n; + + if (!number || (strspn (number, "-0123456789 ") != strlen (number))) + return FALSE; + + n = strtol (number, NULL, 10); + + if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX) + return TRUE; + else + return FALSE; +} + +int is_intpos (char *number) +{ + if (is_integer (number) && atoi (number) > 0) + return TRUE; + else + return FALSE; +} + +/* modified is_intpercent starting from 1% */ +int is_intpercent (char *number) +{ + int i; + if (is_integer (number) && (i = atoi (number)) >= 1 && i <= 100) + return TRUE; + else + return FALSE; +} + +/* entitlement percentage ranges from 1 to 2000% + * a LPAR with minimum entitlement of 0.05 per 1 virtual processor is able to "consume" 2000% CPU */ +int is_intpercent_ent (char *number) +{ + int i; + if (is_integer (number) && (i = atoi (number)) >= 1 && i <= 2000) + return TRUE; + else + return FALSE; +} + +int max_state (int a, int b) +{ + if (a == STATE_CRITICAL || b == STATE_CRITICAL) + return STATE_CRITICAL; + else if (a == STATE_WARNING || b == STATE_WARNING) + return STATE_WARNING; + else if (a == STATE_OK || b == STATE_OK) + return STATE_OK; + else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN) + return STATE_UNKNOWN; + else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT) + return STATE_DEPENDENT; + else + return max (a, b); +} + +/* get monitor status when values are higher than thresholds + * if warn or crit is 0 we assume, the value is not monitored and return STATE_OK */ +int get_status(double value, double warn, double crit) +{ + if (crit > 0 && value > crit) { + return STATE_CRITICAL; + } + if (warn > 0 && value > warn) { + return STATE_WARNING; + } + return STATE_OK; +} + +/* get monitor status when values are higher than thresholds (verbose message included) + * if warn or crit is 0 we assume, the value is not monitored and return STATE_OK */ +int get_new_status(char *verbose_message, double value, double warn, double crit) +{ + int state = STATE_OK; + + if (warn > 0 && value > warn) { + state = STATE_WARNING; + } + if (crit > 0 && value > crit) { + state = STATE_CRITICAL; + } + + if (verbose) { + printf("%s state -> %s (val=%.2f warn>%.2f crit>%.2f)\n", + verbose_message, + states[state], + value, + (warn==0?NAN:warn), /* display NAN means, values was not used for comparison */ + (crit==0?NAN:crit) + ); + } + return state; +} + +/* get monitor status when values are lower than thresholds + * if warn or crit is 0 we assume, the value is not monitored and return STATE_OK */ +int get_lower_status(double value, double warn, double crit) +{ + if (crit > 0 && value < crit) { + return STATE_CRITICAL; + } + if (warn > 0 && value < warn) { + return STATE_WARNING; + } + return STATE_OK; +} + +/* get monitor status when values are lower than thresholds (verbose message included) + * if warn or crit is 0 we assume, the value is not monitored and return STATE_OK */ +int get_new_lower_status(char *verbose_message, double value, double warn, double crit) +{ + int state = STATE_OK; + if (warn > 0 && value < warn) { + state = STATE_WARNING; + } + if (crit > 0 && value < crit) { + state = STATE_CRITICAL; + } + + if (verbose) { + printf("%s state -> %s (val=%.2f warn<%.2f crit<%.2f)\n", + verbose_message, + states[state], + value, + (warn==0?NAN:warn), /* display NAN means, values was not used for comparison */ + (crit==0?NAN:crit) + ); + } + return state; +} + +void print_version(const char *progname,const char *version) +{ + printf("%s v%s\n",progname,version); + exit(0); +} + +void print_usage (void) +{ + printf ("%s\n", _("Usage:")); + printf (" %s [ -pw=limit ] [ -pc=limit ]\n", progname); + printf (" [ -pfw=limit ] [ -pfc=limit ] [ -sw=limit ] [ -sc=limit ]\n"); + printf (" [ -sfw=limit ] [ -sfc=limit ] [ -strict ] [ -i=interval ] [ -h ] [ -v ] [ -V ]\n\n"); +} + +void print_help (void) +{ + printf ("%s %s\n",progname, version); + + printf ("Copyright (c) %s %s <%s>\n",copyright,name,email); + + printf ("%s\n", _("This plugin checks the CPU pool processor utilization on")); + printf ("%s\n", _("AIX shared processor or dedicated donating LPARs and generates an alert if")); + printf ("%s\n", _("values are out of the threshold limits")); + + printf ("\n\n"); + + print_usage (); + + printf (" %s\n", "Pool monitors (only available on shared processor LPARs):"); + + printf (" %s\n", "-pw, --pool-warning=VALUE"); + printf (" %s\n", _("Exit with WARNING status if pool usage is higher than VALUE")); + printf (" %s\n", "-pw, --pool-warning=PERCENT%"); + printf (" %s\n", _("Exit with WARNING status if pool usage is higher than PERCENT of defined")); + printf (" %s\n", _("entitled capacity")); + printf (" %s\n", "-pc, --pool-critical=VALUE"); + printf (" %s\n", _("Exit with CRITICAL status if pool usage is higher than VALUE")); + printf (" %s\n", "-pc, --pool-critical=PERCENT%"); + printf (" %s\n", _("Exit with CRITICAL status if pool usage is higher than PERCENT of defined")); + printf (" %s\n", _("entitled capacity")); + + printf (" %s\n", "-pfw, --pool-free-warning=VALUE"); + printf (" %s\n", _("Exit with WARNING status if pool usage is higher than VALUE")); + printf (" %s\n", "-pfw, --pool-free-warning=PERCENT%"); + printf (" %s\n", _("Exit with WARNING status if pool usage is higher than PERCENT of defined")); + printf (" %s\n", _("entitled capacity")); + printf (" %s\n", "-pfc, --pool-free-critical=VALUE"); + printf (" %s\n", _("Exit with CRITICAL status if pool usage is higher than VALUE")); + printf (" %s\n", "-pfc, --pool-free-critical=PERCENT%"); + printf (" %s\n", _("Exit with CRITICAL status if pool usage is higher than PERCENT of defined")); + printf (" %s\n", _("entitled capacity")); + + printf (" %s\n", "-sw, --system-warning=VALUE"); + printf (" %s\n", _("Exit with WARNING status if system pool usage is higher than VALUE")); + printf (" %s\n", "-sw, --system-warning=PERCENT%"); + printf (" %s\n", _("Exit with WARNING status if system pool usage is higher than PERCENT")); + printf (" %s\n", _("of defined entitled capacity")); + printf (" %s\n", "-sc, --system-critical=VALUE"); + printf (" %s\n", _("Exit with CRITICAL status if system pool usage is higher than VALUE")); + printf (" %s\n", "-sc, --system-critical=PERCENT%"); + printf (" %s\n", _("Exit with CRITICAL status if system pool usage is higher than PERCENT")); + printf (" %s\n", _("of defined entitled capacity")); + + printf (" %s\n", "-sfw, --system-free-warning=VALUE"); + printf (" %s\n", _("Exit with WARNING status if number of free system pool cpus is lower")); + printf (" %s\n", _("than VALUE")); + printf (" %s\n", "-sfw, --system-free-warning=PERCENT%"); + printf (" %s\n", _("Exit with WARNING status if number of free system pool cpus is lower")); + printf (" %s\n", _("than PERCENT of available cpus")); + printf (" %s\n", "-sfc, --system-free-critical=VALUE"); + printf (" %s\n", _("Exit with CRITICAL status if number of free system pool cpus is lower")); + printf (" %s\n", _("than VALUE")); + printf (" %s\n", "-sfc, --system-free-critical=PERCENT%"); + printf (" %s\n", _("Exit with CRITICAL status if number of free system pool cpus is lower")); + printf (" %s\n", _("than PERCENT of available cpus")); + printf ("\n"); + printf (" %s\n", "-i, --interval=INTEGER"); + printf (" %s\n", _("measurement interval in INTEGER seconds (1..30). Default is 1")); + printf (" %s\n", "-x, -strict, --strict"); + printf (" %s\n", _("Exit with CRITICAL status if pool values are obviously wrong")); + printf (" %s\n", _("e.g. pool sizes or usage values are 0, number of pool cpus is higher than")); + printf (" %s\n", _("installed cpus is 0")); + printf (" %s\n", "-v, --verbose"); + printf (" %s\n", _("Show details for command-line debugging")); + printf (" %s\n", "-h, --help"); + printf (" %s\n", _("Print help")); + printf (" %s\n", "-V, --version"); + printf (" %s\n", _("Show plugin version")); + + + printf ("\n"); + printf ("%s\n", _("VALUE is a non-negative floating point number with 1 decimal place e.g. 3.1")); + printf ("%s\n", _("INTEGER is a positive integer number")); + printf ("%s\n", _("PERCENT is a positive integer number in the range 1..100")); + printf ("\n"); + printf ("%s\n", _("Warning and critical checks can be configured independently, critical checks")); + printf ("%s\n", _("without warnings are possible")); + printf ("%s\n", _("Exactly one PERCENT and one VALUE for each option is possible, see examples")); + printf ("\n"); + printf ("%s\n", _("Examples:")); + printf ("\n"); + printf ("%s\n", _("Checks current pool usage for >20 CPUs, >95% and <1 free pool CPU and generate")); + printf ("%s\n", _("critical events only:")); + printf ("%s\n", _("check_cpu_pools -pc 20 -pc 95% -pfc 1")); + printf ("\n"); + printf ("%s\n", _("Checks current system pool usage for >20, >24 CPUs and <2.5, <1 or 98% free")); + printf ("%s\n", _("system pool CPU:")); + printf ("%s\n", _("check_cpu_pools -sw 20 -sc 24 -sfw 2.5 -sfc 1 -sfc 98%")); + + printf ("\n"); + printf ("This nagios plugin comes with ABSOLUTELY NO WARRANTY. You may redistribute\n"); + printf ("copies of the plugin under the terms of the GNU General Public License.\n"); + printf ("For more information about these matters, see the file named COPYING.\n"); + +} + +/* main */ +int main(int argc, char* argv[]) +{ + int c; + int option_index = 0; + + static struct option long_options[] = { + {"pc", required_argument, 0, 'p'}, + {"pool-critical", required_argument, 0, 'p'}, + {"pw", required_argument, 0, 'q'}, + {"pool-warning", required_argument, 0, 'q'}, + {"sc", required_argument, 0, 't'}, + {"system-critical", required_argument, 0, 't'}, + {"sw", required_argument, 0, 's'}, + {"system-warning", required_argument, 0, 's'}, + {"sfc", required_argument, 0, 'g'}, + {"system-free-critical", required_argument, 0, 'g'}, + {"sfw", required_argument, 0, 'k'}, + {"system-free-warning", required_argument, 0, 'k'}, + {"pfc", required_argument, 0, 'l'}, + {"pool-free-critical", required_argument, 0, 'l'}, + {"pfw", required_argument, 0, 'm'}, + {"pool-free-warning", required_argument, 0, 'm'}, + {"strict", no_argument, 0, 'x'}, + {"x", no_argument, 0, 'x'}, + {"i", required_argument, 0, 'i'}, + {"interval", required_argument, 0, 'i'}, + {"verbose", no_argument, 0, 'v'}, + {"version", no_argument, 0, 'V'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + + while (1) { + + c = getopt_long_only (argc, argv, "?Vvh", long_options, &option_index); + if (c == -1 || c == EOF) + break; + + switch (c) { + case 'V': + /* if (verbose) { printf("Option Version selected\n"); } */ + print_version(progname,version); + break; + case 'v': + verbose=TRUE; + /* if (verbose) { printf("Option verbose selected\n"); } */ + break; + case 'p': + /* if (verbose) { printf("Option pool-critical with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( pool_critical_pct != 0 ) { + printf("ERROR: -pc already set to %.0f%%! Don't specify more than once!\n",pool_critical_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + pool_critical_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + pool_check_requested+=1; /* to exit easily later if lpar mode is dedicated donating */ + if ( !(is_intpercent(tmp))) { + printf("ERROR: -pc %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold pool_critical%%=%.0f\n",pool_critical_pct); } + } else { + if ( pool_critical != 0 ) { + printf("ERROR: -pc already set to %.1f! Don't specify more than once!\n",pool_critical); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + pool_critical=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + pool_check_requested+=1; + if ( !(is_positive(optarg))) { + printf("ERROR: -pc %s out of range: Argument has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold pool_critical=%.1f\n",pool_critical); } + } + break; + case 'q': + /* if (verbose) { printf("Option pool-warning with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( pool_warning_pct != 0 ) { + printf("ERROR: -pw already set to %.0f%%! Don't specify more than once!\n",pool_warning_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + pool_warning_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + pool_check_requested+=1; + if ( !(is_intpercent(tmp))) { + printf("ERROR: -pw %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold pool_warning%%=%.0f\n",pool_warning_pct); } + } else { + if ( pool_warning != 0 ) { + printf("ERROR: -pw already set to %.1f! Don't specify more than once!\n",pool_warning); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + pool_warning=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + pool_check_requested+=1; + if ( !(is_positive(optarg))) { + printf("ERROR: -pw %s out of range: Argument has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold pool_warning=%.1f\n",pool_warning); } + } + break; + case 'l': + /* if (verbose) { printf("Option pool-free-critical with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( pool_free_critical_pct != 0 ) { + printf("ERROR: -pfc already set to %.0f%%! Don't specify more than once!\n",pool_free_critical_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + pool_free_critical_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + pool_check_requested+=1; + if ( !(is_intpercent(tmp))) { + printf("ERROR: -pfc %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold pool_free_critical%%=%.0f\n",pool_free_critical_pct); } + } else { + if ( pool_free_critical != 0 ) { + printf("ERROR: -pfc already set to %.1f! Don't specify more than once!\n",pool_free_critical); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + pool_free_critical=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + pool_check_requested+=1; + if ( !(is_positive(optarg))) { + printf("ERROR: -pfc %s out of range: Argument has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold pool_free_critical=%.1f\n",pool_free_critical); } + } + break; + case 'm': + /* if (verbose) { printf("Option pool-free-warning with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( pool_free_warning_pct != 0 ) { + printf("ERROR: -pfw already set to %.0f%%! Don't specify more than once!\n",pool_free_warning_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + pool_free_warning_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + pool_check_requested+=1; + if ( !(is_intpercent(tmp))) { + printf("ERROR: -pfw %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold pool_free_warning%%=%.0f\n",pool_free_warning_pct); } + } else { + if ( pool_free_warning != 0 ) { + printf("ERROR: -pfw already set to %.1f! Don't specify more than once!\n",pool_free_warning); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + pool_free_warning=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + pool_check_requested+=1; + if ( !(is_positive(optarg))) { + printf("ERROR: -pfw %s out of range: Argument has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold pool_free_warning=%.1f\n",pool_free_warning); } + } + break; + case 's': + /* if (verbose) { printf("Option system-warning with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( system_warning_pct != 0 ) { + printf("ERROR: -sw already set to %.0f%%! Don't specify more than once!\n",system_warning_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + system_warning_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + pool_check_requested+=1; + if ( !(is_intpercent(tmp))) { + printf("ERROR: -sw %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold system_warning%%=%.0f\n",system_warning_pct); } + } else { + if ( system_warning != 0 ) { + printf("ERROR: -sw already set to %.1f! Don't specify more than once!\n",system_warning); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + system_warning=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + pool_check_requested+=1; + if ( !(is_positive(optarg))) { + printf("ERROR: -sw %s out of range: Argument has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold system_warning=%.1f\n",system_warning); } + } + break; + case 't': + /* if (verbose) { printf("Option system-critical with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( system_critical_pct != 0 ) { + printf("ERROR: -sc already set to %.0f%%! Don't specify more than once!\n",system_critical_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + system_critical_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + pool_check_requested+=1; + if ( !(is_intpercent(tmp))) { + printf("ERROR: -sc %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold system_critical%%=%.0f\n",system_critical_pct); } + } else { + if ( system_critical != 0 ) { + printf("ERROR: -sc set to %.1f! Don't specify more than once!\n",system_critical); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + system_critical=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + pool_check_requested+=1; + if ( !(is_positive(optarg))) { + printf("ERROR: -sc %s out of range: Argument has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold system_critical=%.1f\n",system_critical); } + } + break; + case 'g': + /* if (verbose) { printf("Option system-free-critical with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( system_free_critical_pct != 0 ) { + printf("ERROR: -sfc already set to %.0f%%! Don't specify more than once!\n",system_free_critical_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + system_free_critical_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + pool_check_requested+=1; + if ( !(is_intpercent(tmp))) { + printf("ERROR: Argument %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold system_free_critical%%=%.0f\n",system_free_critical_pct); } + } else { + if ( system_free_critical != 0 ) { + printf("ERROR: -sfc already set to %.1f! Don't specify more than once!\n",system_free_critical); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + system_free_critical=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + pool_check_requested+=1; + if ( !(is_positive(optarg))) { + printf("ERROR: -sfc %s out of range: Argument has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold system_free_critical=%.1f\n",system_free_critical); } + } + break; + case 'k': + /* if (verbose) { printf("Option system-free-warning with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( system_free_warning_pct != 0 ) { + printf("ERROR: -sfw already set to %.0f%%! Don't specify more than once!\n",system_free_warning_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + system_free_warning_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + pool_check_requested+=1; + if ( !(is_intpercent(tmp))) { + printf("ERROR: -sfw %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold system_free_warning%%=%.0f\n",system_free_warning_pct); } + } else { + if ( system_free_warning != 0 ) { + printf("ERROR: -sfw already set to %.1f! Don't specify more than once!\n",system_free_warning); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + system_free_warning=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + pool_check_requested+=1; + if ( !(is_positive(optarg))) { + printf("ERROR: -sfw %s out of range: Argument has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold system_free_warning=%.1f\n",system_free_warning); } + } + break; + case 'h': + print_help(); + exit(0); + break; + case 'i': + /* if (verbose) { printf("Option interval with %s selected\n",optarg); } */ + if ( is_intpos(optarg)) { + interval = atoi (optarg); + if ( interval > 30 ) { + printf("ERROR: Interval out of range: %s! Allowed range is 1..30!\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + } else { + printf("ERROR: Invalid value for interval: %s! Allowed range is 1..30!\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + break; + case 'x': + /* if (verbose) { printf("Option strict selected\n"); } */ + strict=TRUE; + break; + case '?': + print_help(); + exit(0); + break; + + } + } + + /* check if either one monitor option is used + * you can mix as many options as you want... even if it doesn't make sense at all */ + if ( pool_critical + pool_warning + + pool_critical_pct + pool_warning_pct + + pool_free_critical + pool_free_warning + + pool_free_critical_pct + pool_free_warning_pct + + system_critical + system_warning + + system_critical_pct + system_warning_pct + + system_free_critical + system_free_warning + + system_free_critical_pct + system_free_warning_pct == 0 ) { + printf("ERROR: Specify at least on option -pw, -pc, -pfw, -pfc, -sw, -sc, -sfw, -sfc!\n"); + print_usage(); + exit(STATE_UNKNOWN); + } + + /* 2 structures for difference calculation */ + perfstat_partition_total_t last_lparstats, lparstats; + + /* API variables and helpers */ + u_longlong_t last_time_base; + u_longlong_t last_pool_busy_time, last_shcpu_busy_time; + u_longlong_t last_pool_idle_time = 0; + + u_longlong_t dlt_pool_busy_time, dlt_shcpu_busy_time; + u_longlong_t delta_time_base; + u_longlong_t shcpus_in_sys=0; + double pool_busy_time=0, pool_busy_time_pct=0, shcpu_busy_time=0, shcpu_busy_time_pct=0; + double shcpu_free_time=0, shcpu_free_time_pct=0; + double pool_free_time=0, pool_free_time_pct=0; + int pool_id; + int phys_cpus_pool=0; + + /* retrieve the logical partition metrics */ + if (!perfstat_partition_total(NULL, &last_lparstats, sizeof(perfstat_partition_total_t), 1)) { + printf("CPU_POOLS UNKNOWN Error getting perfstat data from perfstat_partition_total\n"); + exit(STATE_UNKNOWN); + } + + /* Bail out when any pool monitoring is requested and there is no + * pool authority enabled (HMC -> LPAR-name -> Enable performance collection + * or from hmc command line: chsyscfg -m msys -r LPAR -i "LPAR _id=XX,allow_perf_collection=1" */ + if (pool_check_requested && last_lparstats.type.b.shared_enabled && !last_lparstats.type.b.pool_util_authority) { + printf("CPU_POOLS CRITICAL Performance collection is disabled in LPAR profile! Monitoring is not possible!\n"); + exit(STATE_CRITICAL); + } + + /* are we dedicated donating? */ + if(last_lparstats.type.b.donate_enabled) + dedicated_donating = 1; + + /* No entitlement and pool data on dedicated LPARs */ + if ( ! dedicated_donating && ! last_lparstats.type.b.shared_enabled ) { + printf("CPU_POOLS UNKNOWN Entitlement and pool data not available in dedicated LPAR mode\n"); + exit(STATE_UNKNOWN); + } + /* If we run in donating, there is no pool or system pool data at all, only entitlement data + * -> exit with UNKNOWN when still a pool monitoring is requested: + * */ + if ( dedicated_donating && pool_check_requested > 0 ) { + printf("CPU_POOLS UNKNOWN Pool data is not available in dedicated donating mode!\n"); + exit(STATE_UNKNOWN); + } + + sleep(interval); + + /* retrieve the logical partition metrics... again */ + if (!perfstat_partition_total(NULL, &lparstats, sizeof(perfstat_partition_total_t), 1)) { + printf("CPU_POOLS UNKNOWN Error getting perfstat data from perfstat_partition_total\n"); + exit(STATE_UNKNOWN); + } + /* delta pool usage values */ + dlt_pool_busy_time = lparstats.pool_busy_time - last_lparstats.pool_busy_time; + dlt_shcpu_busy_time = lparstats.shcpu_busy_time - last_lparstats.shcpu_busy_time; + + /* get pool sizes */ + phys_cpus_pool = lparstats.phys_cpus_pool; + shcpus_in_sys = lparstats.shcpus_in_sys; + + /* pool id of this lpar */ + pool_id = lparstats.pool_id; + + /* new delta timer */ + delta_time_base = lparstats.timebase_last - last_lparstats.timebase_last; + + /* we run in shared LPAR mode? */ + if (lparstats.type.b.shared_enabled) { + + /* Shared LPAR with pool authority enabled -> we have pool data */ + if (lparstats.type.b.pool_util_authority) { + /* Available Pool Processor (app) */ + pool_free_time=(double)(lparstats.pool_idle_time - last_lparstats.pool_idle_time) / (XINTFRAC*(double)delta_time_base); + pool_free_time_pct=pool_free_time*100/phys_cpus_pool; + + /* busy CPUs in Pool = phys_cpus_pool - app */ + pool_busy_time=(double)dlt_pool_busy_time/(XINTFRAC*(double)delta_time_base); + pool_busy_time_pct= pool_busy_time * 100 / phys_cpus_pool; + + /* busy CPUs in managed system = Shared Pool 0 usage */ + shcpu_busy_time=(double)dlt_shcpu_busy_time/(XINTFRAC*(double)delta_time_base); + shcpu_busy_time_pct=shcpu_busy_time * 100 / (double)shcpus_in_sys; + /* free CPUs in managed system = busy CPUs - shcpus_in_sys */ + shcpu_free_time=shcpus_in_sys - shcpu_busy_time; + shcpu_free_time_pct=shcpu_free_time * 100 / (double)shcpus_in_sys; + } + + /* Compare critical and warning values */ + + /* Pool usage */ + temp_state=get_new_status("Pool usage percentage check", pool_busy_time_pct, pool_warning_pct, pool_critical_pct); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + pool_state = max_state(pool_state, temp_state); /* pool monitor state */ + + temp_state=get_new_status("Pool usage check", pool_busy_time, pool_warning, pool_critical); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + pool_state = max_state(pool_state, temp_state); /* pool monitor state */ + + /* Pool free */ + temp_state=get_new_lower_status("Pool free percentage check", pool_free_time_pct, pool_free_warning_pct, pool_free_critical_pct); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + pool_free_state = max_state(pool_free_state, temp_state); /* pool free monitor state */ + + temp_state=get_new_lower_status("Pool free check", pool_free_time, pool_free_warning, pool_free_critical); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + pool_free_state = max_state(pool_free_state, temp_state); /* pool free monitor state */ + + /* System pool usage */ + temp_state=get_new_status("System pool usage percentage check", shcpu_busy_time_pct, system_warning_pct, system_critical_pct); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + syspool_state = max_state(syspool_state, temp_state); /* system pool state */ + + temp_state=get_new_status("System pool usage check", shcpu_busy_time, system_warning, system_critical); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + syspool_state = max_state(syspool_state, temp_state); /* system pool state */ + + /* System pool free */ + temp_state=get_new_lower_status("System pool free percentage check", shcpu_free_time_pct, system_free_warning_pct, system_free_critical_pct); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + syspool_free_state = max_state(syspool_free_state, temp_state); /* system pool free state */ + + temp_state=get_new_lower_status("System pool free check", shcpu_free_time, system_free_warning, system_free_critical); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + syspool_free_state = max_state(syspool_free_state, temp_state); /* system pool free state */ + + /* when strict checking enabled, do sanity checks too */ + if (strict) { + if ( phys_cpus_pool == 0 || + pool_busy_time == 0 || + shcpus_in_sys == 0 || + shcpu_busy_time == 0 || + phys_cpus_pool > shcpus_in_sys + /* more sanity checks to think about: + * phys_proc_consumed > max_entitlement + * pool_busy_time > phys_cpus_pool + * shcpu_busy_time > shcpus_in_sys */ + ) { + if (verbose) { printf("Insane performance values detected\n" ); } + ent_pool_state=STATE_CRITICAL; + } + + } + + /* human readable output */ + if ( verbose ) { + printf("Pool ID %3d size: %4d, used: %6.2f (%6.2f%%), free: %6.2f (%6.2f%%) \n", + pool_id, + phys_cpus_pool, + pool_busy_time, + pool_busy_time_pct, + pool_free_time, + pool_free_time_pct + ); + printf("System pool size: %4llu, used: %6.2f (%6.2f%%), free: %6.2f (%6.2f%%)\n", + shcpus_in_sys, + shcpu_busy_time, + shcpu_busy_time_pct, + shcpu_free_time, + shcpu_free_time_pct + ); + + + } + + printf("CPU_POOLS %s pool_id=%d pool_size=%d pool_used=%.2f(%s) pool_free=%.2f(%s) syspool_size=%llu syspool_used=%.2f(%s) syspool_free=%.2f(%s) |pool_id=%d;pool_size=%d;pool_used=%.2f;pool_free=%.2f;syspool_size=%llu;syspool_used=%.2f;syspool_free=%.2f\n", + states[ent_pool_state], + pool_id, + phys_cpus_pool, + pool_busy_time, + states[pool_state], + pool_free_time, + states[pool_free_state], + shcpus_in_sys, + shcpu_busy_time, + states[syspool_state], + shcpu_free_time, + states[syspool_free_state], + pool_id, + phys_cpus_pool, + pool_busy_time, + pool_free_time, + shcpus_in_sys, + shcpu_busy_time, + shcpu_free_time + ); + + exit(ent_pool_state); + + + } + /* what to do if we're running in dedicated donating mode: + * phys_proc_consumed contains entitlement usage only if dedicated_donating is set + * if dedicated_donating is not set, this monitor doesn't make sense at all */ + + /* Dedicated LPAR with donating */ + else if ( dedicated_donating ) { + + printf("CPU_POOLS UNKNOWN No pool data available in dedicated donating LPAR mode!\n"); + + exit(STATE_UNKNOWN); + } + + /* No action when dedicated LPAR without donating... we terminated earlier already + * just in case we get here somehow */ + printf("CPU_POOLS UNKNOWN Unknown or unsupported LPAR mode\n"); + exit(STATE_UNKNOWN); +} + +/* This is the end. */ diff --git a/check_ent_pools.c b/check_ent_pools.c new file mode 100644 index 0000000..b56fee4 --- /dev/null +++ b/check_ent_pools.c @@ -0,0 +1,1263 @@ +/* + * monitors entitlement and pool usage (system and other shared pools) on shared processor LPARs + * monitors entitlement usage on dedicated donating LPARs + * not usable on dedicated LPARs + * compiles with IBM xlC and gcc on AIX 5.3(>TL6), 6.1 and 7.1 + * + * Compile with: cc -o check_ent_pools -lperfstat check_ent_pools.c + * + * This nagios plugin comes with ABSOLUTELY NO WARRANTY. You may redistribute + * copies of the plugin under the terms of the GNU General Public License. + * For more information about these matters, see the file named COPYING. +*/ +const char *progname = "check_ent_pools"; +const char *program_name = "check_ent_pools"; +const char *copyright = "2014"; +const char *email = "armink.nagios@gmail.com"; +const char *name = "Armin K"; +const char *version = "1.2"; + +#include +#include +#include +#include +#include +#include +#include + +#ifndef XINTFRAC /* for timebase calculations... */ +#include /* only necessary in AIX 5.3, AIX >=6.1 defines this in libperfstat.h */ +#define XINTFRAC ((double)(_system_configuration.Xint)/(double)(_system_configuration.Xfrac)) +#endif + +/* include GNU getopt_long, since AIX does not provide it */ +#include "getopt_long.h" +#include "getopt_long.c" + +/* define Nagios return codes */ +enum { + STATE_OK, + STATE_WARNING, + STATE_CRITICAL, + STATE_UNKNOWN, + STATE_DEPENDENT +}; + +/* string representations of the return codes */ +char *states[5]={"OK","WARNING","CRITICAL","UNKNOWN","DEPENDENT"}; + +/* initial state values */ +int ent_pool_state=STATE_OK, temp_state=STATE_OK; +int vcpu_busy_state=STATE_OK; +int ent_state=STATE_OK; +int pool_state=STATE_OK, pool_free_state=STATE_OK; +int syspool_state=STATE_OK, syspool_free_state=STATE_OK; + +int dedicated_donating=0; /* marker for dedicated donating mode */ +int interval=1; /* default interval in seconds between the 2 perflib calls = monitoring period */ +int verbose=FALSE; /* only 1 verbose level... violating the plugin recommendations here */ +int strict=FALSE; /* additional sanity checking of various system values */ +int pool_check_requested=0; /* indicator for pool check requests, to react properly when there are no pools to check */ + +/* monitoring variables */ +double entitlement_critical_pct=0, entitlement_warning_pct=0; +double entitlement_critical=0, entitlement_warning=0; +double vcpu_busy_critical_pct=0, vcpu_busy_warning_pct=0; +double pool_critical_pct=0, pool_warning_pct=0; +double pool_critical=0, pool_warning=0; +double pool_free_critical_pct=0, pool_free_warning_pct=0; +double pool_free_critical=0, pool_free_warning=0; +double system_critical_pct=0, system_warning_pct=0; +double system_critical=0, system_warning=0; +double system_free_critical_pct=0, system_free_warning_pct=0; +double system_free_critical=0, system_free_warning=0; + + +/* helper functions "stolen" from util.c and utilbase.c */ +int is_numeric (char *number) +{ + char tmp[1]; + float x; + + if (!number) + return FALSE; + else if (sscanf (number, "%f%c", &x, tmp) == 1) + return TRUE; + else + return FALSE; +} + +int is_positive (char *number) +{ + if (is_numeric (number) && atof (number) > 0.0) + return TRUE; + else + return FALSE; +} + + +int is_percentage (char *number) +{ + int x; + if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100) + return TRUE; + else + return FALSE; +} + +int is_integer (char *number) +{ + long int n; + + if (!number || (strspn (number, "-0123456789 ") != strlen (number))) + return FALSE; + + n = strtol (number, NULL, 10); + + if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX) + return TRUE; + else + return FALSE; +} + +int is_intpos (char *number) +{ + if (is_integer (number) && atoi (number) > 0) + return TRUE; + else + return FALSE; +} + +/* modified is_intpercent starting from 1% */ +int is_intpercent (char *number) +{ + int i; + if (is_integer (number) && (i = atoi (number)) >= 1 && i <= 100) + return TRUE; + else + return FALSE; +} + +/* entitlement percentage ranges from 1 to 2000% + * a LPAR with minimum entitlement of 0.05 per 1 virtual processor is able to "consume" 2000% CPU */ +int is_intpercent_ent (char *number) +{ + int i; + if (is_integer (number) && (i = atoi (number)) >= 1 && i <= 2000) + return TRUE; + else + return FALSE; +} + +int max_state (int a, int b) +{ + if (a == STATE_CRITICAL || b == STATE_CRITICAL) + return STATE_CRITICAL; + else if (a == STATE_WARNING || b == STATE_WARNING) + return STATE_WARNING; + else if (a == STATE_OK || b == STATE_OK) + return STATE_OK; + else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN) + return STATE_UNKNOWN; + else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT) + return STATE_DEPENDENT; + else + return max (a, b); +} + +/* get monitor status when values are higher than thresholds + * if warn or crit is 0 we assume, the value is not monitored and return STATE_OK */ +int get_status(double value, double warn, double crit) +{ + if (crit > 0 && value > crit) { + return STATE_CRITICAL; + } + if (warn > 0 && value > warn) { + return STATE_WARNING; + } + return STATE_OK; +} + +/* get monitor status when values are higher than thresholds (verbose message included) + * if warn or crit is 0 we assume, the value is not monitored and return STATE_OK */ +int get_new_status(char *verbose_message, double value, double warn, double crit) +{ + int state = STATE_OK; + + if (warn > 0 && value > warn) { + state = STATE_WARNING; + } + if (crit > 0 && value > crit) { + state = STATE_CRITICAL; + } + + if (verbose) { + printf("%s state -> %s (val=%.2f warn>%.2f crit>%.2f)\n", + verbose_message, + states[state], + value, + (warn==0?NAN:warn), /* display NAN means, values was not used for comparison */ + (crit==0?NAN:crit) + ); + } + return state; +} + +/* get monitor status when values are lower than thresholds + * if warn or crit is 0 we assume, the value is not monitored and return STATE_OK */ +int get_lower_status(double value, double warn, double crit) +{ + if (crit > 0 && value < crit) { + return STATE_CRITICAL; + } + if (warn > 0 && value < warn) { + return STATE_WARNING; + } + return STATE_OK; +} + +/* get monitor status when values are lower than thresholds (verbose message included) + * if warn or crit is 0 we assume, the value is not monitored and return STATE_OK */ +int get_new_lower_status(char *verbose_message, double value, double warn, double crit) +{ + int state = STATE_OK; + if (warn > 0 && value < warn) { + state = STATE_WARNING; + } + if (crit > 0 && value < crit) { + state = STATE_CRITICAL; + } + + if (verbose) { + printf("%s state -> %s (val=%.2f warn<%.2f crit<%.2f)\n", + verbose_message, + states[state], + value, + (warn==0?NAN:warn), /* display NAN means, values was not used for comparison */ + (crit==0?NAN:crit) + ); + } + return state; +} + +void print_version(const char *progname,const char *version) +{ + printf("%s v%s\n",progname,version); + exit(0); +} + +void print_usage (void) +{ + printf ("%s\n", _("Usage:")); + printf (" %s [ -ec=limit ] [ -ew=limit ] [ -vbw=limit ] [ -vbc=limit ] [ -pw=limit ]\n", progname); + printf (" [ -pc=limit ] [ -pfw=limit ] [ -pfc=limit ] [ -sw=limit ] [ -sc=limit ]\n"); + printf (" [ -sfw=limit ] [ -sfc=limit ] [ -strict ] [ -i=interval ] [ -h ] [ -v ] [ -V ]\n\n"); +} + +void print_help (void) +{ + printf ("%s %s\n",progname, version); + + printf ("Copyright (c) %s %s <%s>\n",copyright,name,email); + + printf ("%s\n", _("This plugin checks the CPU entitlement and/or pool processor utilization on")); + printf ("%s\n", _("AIX shared processor or dedicated donating LPARs and generates an alert if")); + printf ("%s\n", _("values are out of the threshold limits")); + + printf ("\n\n"); + + print_usage (); + + + printf (" %s\n", "Entitlement monitors:"); + printf (" %s\n", "-ew, --entitlement-warning=VALUE"); + printf (" %s\n", _("Exit with WARNING status if entitlement usage is higher than VALUE")); + printf (" %s\n", "-ew, --entitlement-warning=PERCENT%"); + printf (" %s\n", _("Exit with WARNING status if entitlement usage is higher than PERCENT of")); + printf (" %s\n", _("defined entitled capacity")); + printf (" %s\n", "-ec, --entitlement-critical=VALUE"); + printf (" %s\n", _("Exit with CRITICAL status if entitlement usage is higher than VALUE")); + printf (" %s\n", "-ec, --entitlement-critical=PERCENT%"); + printf (" %s\n", _("Exit with CRITICAL status if entitlement usage is higher than PERCENT of")); + printf (" %s\n", _("defined entitled capacity")); + printf ("\n"); + printf (" %s\n", "vCPU monitors:"); + printf (" %s\n", "-vbw, --vpcu-busy-warning=PERCENT%"); + printf (" %s\n", _("Exit with WARNING status if entitlement usage is higher than PERCENT of")); + printf (" %s\n", _("available vCPU capacity")); + printf (" %s\n", "-vbc, --vpcu-busy-critical=PERCENT%"); + printf (" %s\n", _("Exit with CRITICAL status if entitlement usage is higher than PERCENT of")); + printf (" %s\n", _("available vCPU capacity")); + printf ("\n"); + printf (" %s\n", "Pool monitors (only available on shared processor LPARs):"); + + printf (" %s\n", "-pw, --pool-warning=VALUE"); + printf (" %s\n", _("Exit with WARNING status if pool usage is higher than VALUE")); + printf (" %s\n", "-pw, --pool-warning=PERCENT%"); + printf (" %s\n", _("Exit with WARNING status if pool usage is higher than PERCENT of defined")); + printf (" %s\n", _("entitled capacity")); + printf (" %s\n", "-pc, --pool-critical=VALUE"); + printf (" %s\n", _("Exit with CRITICAL status if pool usage is higher than VALUE")); + printf (" %s\n", "-pc, --pool-critical=PERCENT%"); + printf (" %s\n", _("Exit with CRITICAL status if pool usage is higher than PERCENT of defined")); + printf (" %s\n", _("entitled capacity")); + + printf (" %s\n", "-pfw, --pool-free-warning=VALUE"); + printf (" %s\n", _("Exit with WARNING status if pool usage is higher than VALUE")); + printf (" %s\n", "-pfw, --pool-free-warning=PERCENT%"); + printf (" %s\n", _("Exit with WARNING status if pool usage is higher than PERCENT of defined")); + printf (" %s\n", _("entitled capacity")); + printf (" %s\n", "-pfc, --pool-free-critical=VALUE"); + printf (" %s\n", _("Exit with CRITICAL status if pool usage is higher than VALUE")); + printf (" %s\n", "-pfc, --pool-free-critical=PERCENT%"); + printf (" %s\n", _("Exit with CRITICAL status if pool usage is higher than PERCENT of defined")); + printf (" %s\n", _("entitled capacity")); + + printf (" %s\n", "-sw, --system-warning=VALUE"); + printf (" %s\n", _("Exit with WARNING status if system pool usage is higher than VALUE")); + printf (" %s\n", "-sw, --system-warning=PERCENT%"); + printf (" %s\n", _("Exit with WARNING status if system pool usage is higher than PERCENT")); + printf (" %s\n", _("of defined entitled capacity")); + printf (" %s\n", "-sc, --system-critical=VALUE"); + printf (" %s\n", _("Exit with CRITICAL status if system pool usage is higher than VALUE")); + printf (" %s\n", "-sc, --system-critical=PERCENT%"); + printf (" %s\n", _("Exit with CRITICAL status if system pool usage is higher than PERCENT")); + printf (" %s\n", _("of defined entitled capacity")); + + printf (" %s\n", "-sfw, --system-free-warning=VALUE"); + printf (" %s\n", _("Exit with WARNING status if number of free system pool cpus is lower")); + printf (" %s\n", _("than VALUE")); + printf (" %s\n", "-sfw, --system-free-warning=PERCENT%"); + printf (" %s\n", _("Exit with WARNING status if number of free system pool cpus is lower")); + printf (" %s\n", _("than PERCENT of available cpus")); + printf (" %s\n", "-sfc, --system-free-critical=VALUE"); + printf (" %s\n", _("Exit with CRITICAL status if number of free system pool cpus is lower")); + printf (" %s\n", _("than VALUE")); + printf (" %s\n", "-sfc, --system-free-critical=PERCENT%"); + printf (" %s\n", _("Exit with CRITICAL status if number of free system pool cpus is lower")); + printf (" %s\n", _("than PERCENT of available cpus")); + printf ("\n"); + printf (" %s\n", "-i, --interval=INTEGER"); + printf (" %s\n", _("measurement interval in INTEGER seconds (1..30). Default is 1")); + printf (" %s\n", "-x, -strict, --strict"); + printf (" %s\n", _("Exit with CRITICAL status if pool or entitlement values are obviously wrong")); + printf (" %s\n", _("e.g. pool sizes or usage values are 0, number of pool cpus is higher than")); + printf (" %s\n", _("installed cpus, LPAR entitlement or CPU usage is 0")); + printf (" %s\n", "-v, --verbose"); + printf (" %s\n", _("Show details for command-line debugging")); + printf (" %s\n", "-h, --help"); + printf (" %s\n", _("Print help")); + printf (" %s\n", "-V, --version"); + printf (" %s\n", _("Show plugin version")); + + + printf ("\n"); + printf ("%s\n", _("VALUE is a non-negative floating point number with 1 decimal place e.g. 3.1")); + printf ("%s\n", _("INTEGER is a positive integer number")); + printf ("%s\n", _("PERCENT is a positive integer number in the range 1..100")); + printf ("%s\n", _("PERCENT in entitlement arguments are in the range 1..2000")); + printf ("\n"); + printf ("%s\n", _("Warning and critical checks can be configured independently, critical checks")); + printf ("%s\n", _("without warnings are possible")); + printf ("%s\n", _("Exactly one PERCENT and one VALUE for each option is possible, see examples")); + printf ("\n"); + printf ("%s\n", _("Examples:")); + printf ("\n"); + printf ("%s\n", _("Checks entitlement usage at 2.0 and 2.5 or 200%:")); + printf ("%s\n", _("check_ent_pools -ew 2.0 -ec 2.5 -ec 200%")); + printf ("\n"); + printf ("%s\n", _("Checks entitlement usage at 100% and 300%:")); + printf ("%s\n", _("check_ent_pools -ew 100% -ec 300%")); + printf ("\n"); + printf ("%s\n", _("Checks current pool usage for >20 CPUs, >95% and <1 free pool CPU and generate")); + printf ("%s\n", _("critical events only:")); + printf ("%s\n", _("check_ent_pools -pc 20 -pc 95% -pfc 1")); + printf ("\n"); + printf ("%s\n", _("Checks current system pool usage for >20, >24 CPUs and <2.5, <1 or 98% free")); + printf ("%s\n", _("system pool CPU:")); + printf ("%s\n", _("check_ent_pools -sw 20 -sc 24 -sfw 2.5 -sfc 1 -sfc 98%")); + + printf ("\n"); + printf ("This nagios plugin comes with ABSOLUTELY NO WARRANTY. You may redistribute\n"); + printf ("copies of the plugin under the terms of the GNU General Public License.\n"); + printf ("For more information about these matters, see the file named COPYING.\n"); + +} + +/* main */ +int main(int argc, char* argv[]) +{ + int c; + int option_index = 0; + + static struct option long_options[] = { + {"ec", required_argument, 0, 'e'}, + {"entitlement-critical", required_argument, 0, 'e'}, + {"ew", required_argument, 0, 'f'}, + {"entitlement-warning", required_argument, 0, 'f'}, + {"vbw", required_argument, 0, 'a'}, + {"virtual-busy-warning", required_argument, 0, 'a'}, + {"vbc", required_argument, 0, 'b'}, + {"virtual-busy-critical",required_argument, 0, 'b'}, + {"pc", required_argument, 0, 'p'}, + {"pool-critical", required_argument, 0, 'p'}, + {"pw", required_argument, 0, 'q'}, + {"pool-warning", required_argument, 0, 'q'}, + {"sc", required_argument, 0, 't'}, + {"system-critical", required_argument, 0, 't'}, + {"sw", required_argument, 0, 's'}, + {"system-warning", required_argument, 0, 's'}, + {"sfc", required_argument, 0, 'g'}, + {"system-free-critical", required_argument, 0, 'g'}, + {"sfw", required_argument, 0, 'k'}, + {"system-free-warning", required_argument, 0, 'k'}, + {"pfc", required_argument, 0, 'l'}, + {"pool-free-critical", required_argument, 0, 'l'}, + {"pfw", required_argument, 0, 'm'}, + {"pool-free-warning", required_argument, 0, 'm'}, + {"strict", no_argument, 0, 'x'}, + {"x", no_argument, 0, 'x'}, + {"i", required_argument, 0, 'i'}, + {"interval", required_argument, 0, 'i'}, + {"verbose", no_argument, 0, 'v'}, + {"version", no_argument, 0, 'V'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + + while (1) { + + c = getopt_long_only (argc, argv, "?Vvh", long_options, &option_index); + if (c == -1 || c == EOF) + break; + + switch (c) { + case 'V': + /* if (verbose) { printf("Option Version selected\n"); } */ + print_version(progname,version); + break; + case 'v': + verbose=TRUE; + /* if (verbose) { printf("Option verbose selected\n"); } */ + break; + case 'e': + /* if (verbose) { printf("Option entitlement-critical with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( entitlement_critical_pct != 0 ) { + printf("ERROR: -ec already set to %.0f%%! Don't specify more than once!\n",entitlement_critical_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..2000% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + entitlement_critical_pct = (double)atoi(optarg); /* pct ranges from 1 to 2000% for shared LPARs */ + /* maximum percentage is 2000% only on LPARs with minimum entitlement of 0.05 per virtual processor + * effective maximum percentage decreases when entitlement is increased, this is currently not checked for sanity */ + if ( !(is_intpercent_ent(tmp))) { + printf("ERROR: -ec %s%% out of range! Allowed 1%%..2000%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold entitlement_critical%%=%.0f%%\n",entitlement_critical_pct); } + } else { + if ( entitlement_critical != 0 ) { + printf("ERROR: -ec already set to %.1f! Don't specify more than once!\n",entitlement_critical); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int =(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + entitlement_critical=(double)tmp_int/10; + if ( !(is_positive(optarg))) { + printf("ERROR: -ec %s out of range: Entitlement has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold entitlement_critical=%.1f\n",entitlement_critical); } + } + break; + case 'f': + /* if (verbose) { printf("Option entitlement-warning with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( entitlement_warning_pct != 0 ) { + printf("ERROR: -ew already set to %.0f%%! Don't specify more than once!\n",entitlement_warning_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..2000% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + entitlement_warning_pct= (double)atoi(optarg); /* pct ranges from 1 to 2000% for shared LPARs */ + /* maximum percentage is 2000% only on LPARs with minimum entitlement of 0.05 per virtual processor + * effective maximum percentage decreases when entitlement is increased, this is currently not checked for sanity */ + if ( !(is_intpercent_ent(tmp))) { + printf("ERROR: -ew %s%% out of range! Allowed 1%%..2000%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold entitlement_warning%%=%.0f%%\n",entitlement_warning_pct); } + } else { + if ( entitlement_warning != 0 ) { + printf("ERROR: -ew already set to %.1f! Don't specify more than once!\n",entitlement_warning); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + entitlement_warning=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + if ( !(is_positive(optarg))) { + printf("ERROR: -ew %s out of range: Entitlement has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold entitlement_warning=%.1f\n",entitlement_warning); } + } + break; + case 'a': + /* if (verbose) { printf("Option vcpu-busy-warning with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( vcpu_busy_warning_pct != 0 ) { + printf("ERROR: -vbw already set to %.0f%%! Don't specify more than once!\n",vcpu_busy_warning_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + vcpu_busy_warning_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + if ( !(is_intpercent(tmp))) { + printf("ERROR: -vbw %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold vcpu_busy_warning%%=%.0f\n",vcpu_busy_warning_pct); } + } else { + /* optarg is floating value or anything else */ + printf("ERROR: -vbw %s out of range: Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + break; + case 'b': + /* if (verbose) { printf("Option vcpu-busy-critical with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( vcpu_busy_critical_pct != 0 ) { + printf("ERROR: -vbc already set to %.0f%%! Don't specify more than once!\n",vcpu_busy_critical_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + vcpu_busy_critical_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + if ( !(is_intpercent(tmp))) { + printf("ERROR: -vbc %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold vcpu_busy_critical%%=%.0f\n",vcpu_busy_critical_pct); } + } else { + /* optarg is floating value or anything else */ + printf("ERROR: -vbc %s out of range: Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + break; + case 'p': + /* if (verbose) { printf("Option pool-critical with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( pool_critical_pct != 0 ) { + printf("ERROR: -pc already set to %.0f%%! Don't specify more than once!\n",pool_critical_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + pool_critical_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + pool_check_requested+=1; /* to exit easily later if lpar mode is dedicated donating */ + if ( !(is_intpercent(tmp))) { + printf("ERROR: -pc %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold pool_critical%%=%.0f\n",pool_critical_pct); } + } else { + if ( pool_critical != 0 ) { + printf("ERROR: -pc already set to %.1f! Don't specify more than once!\n",pool_critical); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + pool_critical=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + pool_check_requested+=1; + if ( !(is_positive(optarg))) { + printf("ERROR: -pc %s out of range: Argument has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold pool_critical=%.1f\n",pool_critical); } + } + break; + case 'q': + /* if (verbose) { printf("Option pool-warning with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( pool_warning_pct != 0 ) { + printf("ERROR: -pw already set to %.0f%%! Don't specify more than once!\n",pool_warning_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + pool_warning_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + pool_check_requested+=1; + if ( !(is_intpercent(tmp))) { + printf("ERROR: -pw %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold pool_warning%%=%.0f\n",pool_warning_pct); } + } else { + if ( pool_warning != 0 ) { + printf("ERROR: -pw already set to %.1f! Don't specify more than once!\n",pool_warning); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + pool_warning=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + pool_check_requested+=1; + if ( !(is_positive(optarg))) { + printf("ERROR: -pw %s out of range: Argument has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold pool_warning=%.1f\n",pool_warning); } + } + break; + case 'l': + /* if (verbose) { printf("Option pool-free-critical with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( pool_free_critical_pct != 0 ) { + printf("ERROR: -pfc already set to %.0f%%! Don't specify more than once!\n",pool_free_critical_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + pool_free_critical_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + pool_check_requested+=1; + if ( !(is_intpercent(tmp))) { + printf("ERROR: -pfc %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold pool_free_critical%%=%.0f\n",pool_free_critical_pct); } + } else { + if ( pool_free_critical != 0 ) { + printf("ERROR: -pfc already set to %.1f! Don't specify more than once!\n",pool_free_critical); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + pool_free_critical=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + pool_check_requested+=1; + if ( !(is_positive(optarg))) { + printf("ERROR: -pfc %s out of range: Argument has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold pool_free_critical=%.1f\n",pool_free_critical); } + } + break; + case 'm': + /* if (verbose) { printf("Option pool-free-warning with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( pool_free_warning_pct != 0 ) { + printf("ERROR: -pfw already set to %.0f%%! Don't specify more than once!\n",pool_free_warning_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + pool_free_warning_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + pool_check_requested+=1; + if ( !(is_intpercent(tmp))) { + printf("ERROR: -pfw %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold pool_free_warning%%=%.0f\n",pool_free_warning_pct); } + } else { + if ( pool_free_warning != 0 ) { + printf("ERROR: -pfw already set to %.1f! Don't specify more than once!\n",pool_free_warning); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + pool_free_warning=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + pool_check_requested+=1; + if ( !(is_positive(optarg))) { + printf("ERROR: -pfw %s out of range: Argument has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold pool_free_warning=%.1f\n",pool_free_warning); } + } + break; + case 's': + /* if (verbose) { printf("Option system-warning with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( system_warning_pct != 0 ) { + printf("ERROR: -sw already set to %.0f%%! Don't specify more than once!\n",system_warning_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + system_warning_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + pool_check_requested+=1; + if ( !(is_intpercent(tmp))) { + printf("ERROR: -sw %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold system_warning%%=%.0f\n",system_warning_pct); } + } else { + if ( system_warning != 0 ) { + printf("ERROR: -sw already set to %.1f! Don't specify more than once!\n",system_warning); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + system_warning=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + pool_check_requested+=1; + if ( !(is_positive(optarg))) { + printf("ERROR: -sw %s out of range: Argument has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold system_warning=%.1f\n",system_warning); } + } + break; + case 't': + /* if (verbose) { printf("Option system-critical with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( system_critical_pct != 0 ) { + printf("ERROR: -sc already set to %.0f%%! Don't specify more than once!\n",system_critical_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + system_critical_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + pool_check_requested+=1; + if ( !(is_intpercent(tmp))) { + printf("ERROR: -sc %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold system_critical%%=%.0f\n",system_critical_pct); } + } else { + if ( system_critical != 0 ) { + printf("ERROR: -sc set to %.1f! Don't specify more than once!\n",system_critical); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + system_critical=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + pool_check_requested+=1; + if ( !(is_positive(optarg))) { + printf("ERROR: -sc %s out of range: Argument has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold system_critical=%.1f\n",system_critical); } + } + break; + case 'g': + /* if (verbose) { printf("Option system-free-critical with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( system_free_critical_pct != 0 ) { + printf("ERROR: -sfc already set to %.0f%%! Don't specify more than once!\n",system_free_critical_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + system_free_critical_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + pool_check_requested+=1; + if ( !(is_intpercent(tmp))) { + printf("ERROR: Argument %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold system_free_critical%%=%.0f\n",system_free_critical_pct); } + } else { + if ( system_free_critical != 0 ) { + printf("ERROR: -sfc already set to %.1f! Don't specify more than once!\n",system_free_critical); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + system_free_critical=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + pool_check_requested+=1; + if ( !(is_positive(optarg))) { + printf("ERROR: -sfc %s out of range: Argument has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold system_free_critical=%.1f\n",system_free_critical); } + } + break; + case 'k': + /* if (verbose) { printf("Option system-free-warning with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( system_free_warning_pct != 0 ) { + printf("ERROR: -sfw already set to %.0f%%! Don't specify more than once!\n",system_free_warning_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + system_free_warning_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + pool_check_requested+=1; + if ( !(is_intpercent(tmp))) { + printf("ERROR: -sfw %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold system_free_warning%%=%.0f\n",system_free_warning_pct); } + } else { + if ( system_free_warning != 0 ) { + printf("ERROR: -sfw already set to %.1f! Don't specify more than once!\n",system_free_warning); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + system_free_warning=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + pool_check_requested+=1; + if ( !(is_positive(optarg))) { + printf("ERROR: -sfw %s out of range: Argument has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold system_free_warning=%.1f\n",system_free_warning); } + } + break; + case 'h': + print_help(); + exit(0); + break; + case 'i': + /* if (verbose) { printf("Option interval with %s selected\n",optarg); } */ + if ( is_intpos(optarg)) { + interval = atoi (optarg); + if ( interval > 30 ) { + printf("ERROR: Interval out of range: %s! Allowed range is 1..30!\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + } else { + printf("ERROR: Invalid value for interval: %s! Allowed range is 1..30!\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + break; + case 'x': + /* if (verbose) { printf("Option strict selected\n"); } */ + strict=TRUE; + break; + case '?': + print_help(); + exit(0); + break; + + } + } + + /* check if either one monitor option is used + * you can mix as many options as you want... even if it doesn't make sense at all */ + if ( entitlement_critical+ + entitlement_critical_pct+ + entitlement_warning + + entitlement_warning_pct + + vcpu_busy_warning_pct + + vcpu_busy_critical_pct + + pool_critical + pool_warning + + pool_critical_pct + pool_warning_pct + + pool_free_critical + pool_free_warning + + pool_free_critical_pct + pool_free_warning_pct + + system_critical + system_warning + + system_critical_pct + system_warning_pct + + system_free_critical + system_free_warning + + system_free_critical_pct + system_free_warning_pct == 0 ) { + printf("ERROR: Specify at least on option -ew, -ec, -vbw, vbc, -pw, -pc, -pfw, -pfc, -sw, -sc, -sfw, -sfc!\n"); + print_usage(); + exit(STATE_UNKNOWN); + } + + /* 2 structures for difference calculation */ + perfstat_partition_total_t last_lparstats, lparstats; + + /* API variables and helpers */ + u_longlong_t last_time_base; + u_longlong_t last_pcpu_user, last_pcpu_sys, last_pcpu_idle, last_pcpu_wait; + u_longlong_t last_pool_busy_time, last_shcpu_busy_time; + u_longlong_t last_pool_idle_time = 0; + + u_longlong_t dlt_pcpu_user, dlt_pcpu_sys, dlt_pcpu_idle, dlt_pcpu_wait; + u_longlong_t dlt_pool_busy_time, dlt_shcpu_busy_time; + u_longlong_t delta_time_base; + u_longlong_t delta_purr; + u_longlong_t shcpus_in_sys=0; + double pool_busy_time=0, pool_busy_time_pct=0, shcpu_busy_time=0, shcpu_busy_time_pct=0; + double shcpu_free_time=0, shcpu_free_time_pct=0; + double pool_free_time=0, pool_free_time_pct=0; + double phys_proc_consumed=0, entitlement=0, percent_ent=0, vcpu_busy=0; + int pool_id; + int phys_cpus_pool=0; + int max_entitlement=0; + + /* retrieve the logical partition metrics */ + if (!perfstat_partition_total(NULL, &last_lparstats, sizeof(perfstat_partition_total_t), 1)) { + printf("ENT_POOLS UNKNOWN Error getting perfstat data from perfstat_partition_total\n"); + exit(STATE_UNKNOWN); + } + + /* Bail out when any pool monitoring is requested and there is no + * pool authority enabled (HMC -> LPAR-name -> Enable performance collection + * or from hmc command line: chsyscfg -m msys -r LPAR -i "LPAR _id=XX,allow_perf_collection=1" */ + if (pool_check_requested && last_lparstats.type.b.shared_enabled && !last_lparstats.type.b.pool_util_authority) { + printf("ENT_POOLS CRITICAL Performance collection is disabled in LPAR profile! Monitoring is not possible!\n"); + exit(STATE_CRITICAL); + } + + /* are we dedicated donating? */ + if(last_lparstats.type.b.donate_enabled) + dedicated_donating = 1; + + /* No entitlement and pool data on dedicated LPARs */ + if ( ! dedicated_donating && ! last_lparstats.type.b.shared_enabled ) { + printf("ENT_POOLS UNKNOWN Entitlement and pool data not available in dedicated LPAR mode\n"); + exit(STATE_UNKNOWN); + } + /* If we run in donating, there is no pool or system pool data at all, only entitlement data + * -> exit with UNKNOWN when still a pool monitoring is requested: + * */ + if ( dedicated_donating && pool_check_requested > 0 ) { + printf("ENT_POOLS UNKNOWN Pool data is not available in dedicated donating mode!\n"); + exit(STATE_UNKNOWN); + } + + sleep(interval); + + /* retrieve the logical partition metrics... again */ + if (!perfstat_partition_total(NULL, &lparstats, sizeof(perfstat_partition_total_t), 1)) { + printf("ENT_POOLS UNKNOWN Error getting perfstat data from perfstat_partition_total\n"); + exit(STATE_UNKNOWN); + } + + /* all last_* values were set in the previous run, the deltas is what we want */ + /* physc consists of usr+sys+wait+idle */ + dlt_pcpu_user = lparstats.puser - last_lparstats.puser; + dlt_pcpu_sys = lparstats.psys - last_lparstats.psys; + dlt_pcpu_idle = lparstats.pidle - last_lparstats.pidle; + dlt_pcpu_wait = lparstats.pwait - last_lparstats.pwait; + + delta_purr = dlt_pcpu_user + dlt_pcpu_sys + dlt_pcpu_idle + dlt_pcpu_wait; + + /* delta pool usage values */ + dlt_pool_busy_time = lparstats.pool_busy_time - last_lparstats.pool_busy_time; + dlt_shcpu_busy_time = lparstats.shcpu_busy_time - last_lparstats.shcpu_busy_time; + + /* get pool sizes */ + phys_cpus_pool = lparstats.phys_cpus_pool; + shcpus_in_sys = lparstats.shcpus_in_sys; + + /* pool id of this lpar */ + pool_id = lparstats.pool_id; + + /* get entitlement of lpar */ + entitlement = (double)lparstats.entitled_proc_capacity / 100.0 ; + + /* get number of virtual processors = maximum entitlement */ + max_entitlement = lparstats.online_cpus; + + /* new delta timer */ + delta_time_base = lparstats.timebase_last - last_lparstats.timebase_last; + + /* Physical Processor Consumed = Entitlement Consumed */ + phys_proc_consumed = (double)delta_purr / (double)delta_time_base; + + /* Percentage of Entitlement Consumed */ + percent_ent = (phys_proc_consumed / entitlement) * 100; + + /* Percentage of vCPU busy */ + vcpu_busy = (phys_proc_consumed / (double)max_entitlement) * 100; + + /* we run in shared LPAR mode? */ + if (lparstats.type.b.shared_enabled) { + + /* Shared LPAR with pool authority enabled -> we have pool data */ + if (lparstats.type.b.pool_util_authority) { + /* Available Pool Processor (app) */ + pool_free_time=(double)(lparstats.pool_idle_time - last_lparstats.pool_idle_time) / (XINTFRAC*(double)delta_time_base); + pool_free_time_pct=pool_free_time*100/phys_cpus_pool; + + /* busy CPUs in Pool = phys_cpus_pool - app */ + pool_busy_time=(double)dlt_pool_busy_time/(XINTFRAC*(double)delta_time_base); + pool_busy_time_pct= pool_busy_time * 100 / phys_cpus_pool; + + /* busy CPUs in managed system = Shared Pool 0 usage */ + shcpu_busy_time=(double)dlt_shcpu_busy_time/(XINTFRAC*(double)delta_time_base); + shcpu_busy_time_pct=shcpu_busy_time * 100 / (double)shcpus_in_sys; + /* free CPUs in managed system = busy CPUs - shcpus_in_sys */ + shcpu_free_time=shcpus_in_sys - shcpu_busy_time; + shcpu_free_time_pct=shcpu_free_time * 100 / (double)shcpus_in_sys; + } + + /* Compare critical and warning values */ + + /* Entitlement checks */ + /* maximum percentage is 2000% only on LPARs with minimum entitlement of 0.05 per virtual processor + * effective maximum percentage decreases when entitlement is increased, this is currently not checked for sanity */ + temp_state=get_new_status("Entitlement percentage check", percent_ent, entitlement_warning_pct, entitlement_critical_pct); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + ent_state = max_state(ent_state, temp_state); /* entitlement monitor state */ + + temp_state=get_new_status("Entitlement check", phys_proc_consumed, entitlement_warning, entitlement_critical); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + ent_state = max_state(ent_state, temp_state); /* entitlement monitor state */ + + /* vCPU busy checks */ + temp_state=get_new_status("vCPU busy percentage check",vcpu_busy, vcpu_busy_warning_pct, vcpu_busy_critical_pct); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + vcpu_busy_state = max_state(ent_state,temp_state); /* vcpu busy monitor state */ + + /* Pool usage */ + temp_state=get_new_status("Pool usage percentage check", pool_busy_time_pct, pool_warning_pct, pool_critical_pct); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + pool_state = max_state(pool_state, temp_state); /* pool monitor state */ + + temp_state=get_new_status("Pool usage check", pool_busy_time, pool_warning, pool_critical); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + pool_state = max_state(pool_state, temp_state); /* pool monitor state */ + + /* Pool free */ + temp_state=get_new_lower_status("Pool free percentage check", pool_free_time_pct, pool_free_warning_pct, pool_free_critical_pct); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + pool_free_state = max_state(pool_free_state, temp_state); /* pool free monitor state */ + + temp_state=get_new_lower_status("Pool free check", pool_free_time, pool_free_warning, pool_free_critical); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + pool_free_state = max_state(pool_free_state, temp_state); /* pool free monitor state */ + + /* System pool usage */ + temp_state=get_new_status("System pool usage percentage check", shcpu_busy_time_pct, system_warning_pct, system_critical_pct); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + syspool_state = max_state(syspool_state, temp_state); /* system pool state */ + + temp_state=get_new_status("System pool usage check", shcpu_busy_time, system_warning, system_critical); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + syspool_state = max_state(syspool_state, temp_state); /* system pool state */ + + /* System pool free */ + temp_state=get_new_lower_status("System pool free percentage check", shcpu_free_time_pct, system_free_warning_pct, system_free_critical_pct); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + syspool_free_state = max_state(syspool_free_state, temp_state); /* system pool free state */ + + temp_state=get_new_lower_status("System pool free check", shcpu_free_time, system_free_warning, system_free_critical); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + syspool_free_state = max_state(syspool_free_state, temp_state); /* system pool free state */ + + /* when strict checking enabled, do sanity checks too */ + if (strict) { + if ( phys_proc_consumed == 0 || + entitlement == 0 || + phys_cpus_pool == 0 || + pool_busy_time == 0 || + shcpus_in_sys == 0 || + shcpu_busy_time == 0 || + phys_cpus_pool > shcpus_in_sys + /* more sanity checks to think about: + * phys_proc_consumed > max_entitlement + * pool_busy_time > phys_cpus_pool + * shcpu_busy_time > shcpus_in_sys */ + ) { + if (verbose) { printf("Insane performance values detected\n" ); } + ent_pool_state=STATE_CRITICAL; + } + + } + + /* human readable output */ + if ( verbose ) { + printf("\nEntitlement used: %.2f (%.2f%%), desired: %.2f, max: %.2f, vCPU busy: %6.2f%%\n", + phys_proc_consumed, + percent_ent, + entitlement, + (double)max_entitlement, + vcpu_busy + ); + printf("Pool ID %3d size: %4d, used: %6.2f (%6.2f%%), free: %6.2f (%6.2f%%) \n", + pool_id, + phys_cpus_pool, + pool_busy_time, + pool_busy_time_pct, + pool_free_time, + pool_free_time_pct + ); + printf("System pool size: %4llu, used: %6.2f (%6.2f%%), free: %6.2f (%6.2f%%)\n", + shcpus_in_sys, + shcpu_busy_time, + shcpu_busy_time_pct, + shcpu_free_time, + shcpu_free_time_pct + ); + + + } + + printf("ENT_POOLS %s ent_used=%.2f(%s) ent=%.2f ent_max=%d vcpu_busy=%.2f%%(%s) pool_id=%d pool_size=%d pool_used=%.2f(%s) pool_free=%.2f(%s) syspool_size=%llu syspool_used=%.2f(%s) syspool_free=%.2f(%s) |ent_used=%.2f;ent=%.2f;ent_max=%d;vcpu_busy=%.2f;pool_id=%d;pool_size=%d;pool_used=%.2f;pool_free=%.2f;syspool_size=%llu;syspool_used=%.2f;syspool_free=%.2f\n", + states[ent_pool_state], + phys_proc_consumed, + states[ent_state], + entitlement, + max_entitlement, + vcpu_busy, + states[vcpu_busy_state], + pool_id, + phys_cpus_pool, + pool_busy_time, + states[pool_state], + pool_free_time, + states[pool_free_state], + shcpus_in_sys, + shcpu_busy_time, + states[syspool_state], + shcpu_free_time, + states[syspool_free_state], + phys_proc_consumed, + entitlement, + max_entitlement, + vcpu_busy, + pool_id, + phys_cpus_pool, + pool_busy_time, + pool_free_time, + shcpus_in_sys, + shcpu_busy_time, + shcpu_free_time + ); + + exit(ent_pool_state); + + + } + /* what to do if we're running in dedicated donating mode: + * phys_proc_consumed contains entitlement usage only if dedicated_donating is set + * if dedicated_donating is not set, this monitor doesn't make sense at all */ + + /* Dedicated LPAR with donating */ + else if ( dedicated_donating ) { + + /* Entitlement checks */ + /* the effective maximum percentage is 100% with dedicated donating, but you can still enter 2000% on the command-line + * this is currently not checked for sanity :-) */ + temp_state=get_new_status("Entitlement percentage check", percent_ent, entitlement_warning_pct, entitlement_critical_pct); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* global monitor state */ + ent_state = max_state(ent_state,temp_state); /* entitlement monitor state */ + + temp_state=get_new_status("Entitlement check", phys_proc_consumed, entitlement_warning, entitlement_critical); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* global monitor state */ + ent_state = max_state(ent_state,temp_state); /* entitlement monitor state */ + + /* vCPU busy checks */ + temp_state=get_new_status("vCPU busy percentage check", vcpu_busy, vcpu_busy_warning_pct, vcpu_busy_critical_pct); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + vcpu_busy_state = max_state(ent_state,temp_state); /* vcpu busy monitor state */ + + /* when strict checking enabled, do sanity checks too */ + if (strict) { + if ( phys_proc_consumed == 0 || + entitlement == 0 + ) { + if (verbose) { printf("Insane performance values detected\n" ); } + ent_pool_state=STATE_CRITICAL; + } + } + + /* human readable output */ + if ( verbose ) { + printf("Entitlement used: %.2f (%.2f%%), desired: %.2f, max: %.2f vCPU busy: %6.2f%%\n", + phys_proc_consumed, + percent_ent, + entitlement, + (double)max_entitlement, + vcpu_busy + ); + } + + printf("ENT_POOLS %s ent_used=%.2f(%s) ent=%.2f ent_max=%d vcpu_busy=%.2f%% |ent_used=%.2f;ent=%.2f;ent_max=%d;vcpu_busy=%.2f\n", + states[ent_pool_state], + phys_proc_consumed, + states[ent_state], + entitlement, + max_entitlement, + vcpu_busy, + phys_proc_consumed, + entitlement, + max_entitlement, + vcpu_busy + ); + + exit(ent_pool_state); + } + + /* No action when dedicated LPAR without donating... we terminated earlier already + * just in case we get here somehow */ + printf("ENT_POOLS UNKNOWN Unknown or unsupported LPAR mode\n"); + exit(STATE_UNKNOWN); +} + +/* This is the end. */ diff --git a/check_entitlement.c b/check_entitlement.c new file mode 100644 index 0000000..1ae427e --- /dev/null +++ b/check_entitlement.c @@ -0,0 +1,734 @@ +/* + * monitors entitlement usage on shared processor LPARs + * monitors entitlement usage on dedicated donating LPARs + * not usable on dedicated LPARs + * compiles with IBM xlC and gcc on AIX 5.3(>TL6), 6.1 and 7.1 + * + * Compile with: cc -o check_entitlement -lperfstat check_entitlement.c + * + * This is stripped down from check_ent_pools.c, only pool parts removed + * + * This nagios plugin comes with ABSOLUTELY NO WARRANTY. You may redistribute + * copies of the plugin under the terms of the GNU General Public License. + * For more information about these matters, see the file named COPYING. +*/ +const char *progname = "check_entitlement"; +const char *program_name = "check_entitlement"; +const char *copyright = "2014"; +const char *email = "armink.nagios@gmail.com"; +const char *name = "Armin K"; +const char *version = "1.2"; + +#include +#include +#include +#include +#include +#include +#include + +#ifndef XINTFRAC /* for timebase calculations... */ +#include /* only necessary in AIX 5.3, AIX >=6.1 defines this in libperfstat.h */ +#define XINTFRAC ((double)(_system_configuration.Xint)/(double)(_system_configuration.Xfrac)) +#endif + +/* include GNU getopt_long, since AIX does not provide it */ +#include "getopt_long.h" +#include "getopt_long.c" + +/* define Nagios return codes */ +enum { + STATE_OK, + STATE_WARNING, + STATE_CRITICAL, + STATE_UNKNOWN, + STATE_DEPENDENT +}; + +/* string representations of the return codes */ +char *states[5]={"OK","WARNING","CRITICAL","UNKNOWN","DEPENDENT"}; + +/* initial state values */ +int ent_pool_state=STATE_OK, temp_state=STATE_OK; +int vcpu_busy_state=STATE_OK; +int ent_state=STATE_OK; + +int dedicated_donating=0; /* marker for dedicated donating mode */ +int interval=1; /* default interval in seconds between the 2 perflib calls = monitoring period */ +int verbose=FALSE; /* only 1 verbose level... violating the plugin recommendations here */ +int strict=FALSE; /* additional sanity checking of various system values */ + +/* monitoring variables */ +double entitlement_critical_pct=0, entitlement_warning_pct=0; +double entitlement_critical=0, entitlement_warning=0; +double vcpu_busy_critical_pct=0, vcpu_busy_warning_pct=0; + + +/* helper functions "stolen" from util.c and utilbase.c */ +int is_numeric (char *number) +{ + char tmp[1]; + float x; + + if (!number) + return FALSE; + else if (sscanf (number, "%f%c", &x, tmp) == 1) + return TRUE; + else + return FALSE; +} + +int is_positive (char *number) +{ + if (is_numeric (number) && atof (number) > 0.0) + return TRUE; + else + return FALSE; +} + + +int is_percentage (char *number) +{ + int x; + if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100) + return TRUE; + else + return FALSE; +} + +int is_integer (char *number) +{ + long int n; + + if (!number || (strspn (number, "-0123456789 ") != strlen (number))) + return FALSE; + + n = strtol (number, NULL, 10); + + if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX) + return TRUE; + else + return FALSE; +} + +int is_intpos (char *number) +{ + if (is_integer (number) && atoi (number) > 0) + return TRUE; + else + return FALSE; +} + +/* modified is_intpercent starting from 1% */ +int is_intpercent (char *number) +{ + int i; + if (is_integer (number) && (i = atoi (number)) >= 1 && i <= 100) + return TRUE; + else + return FALSE; +} + +/* entitlement percentage ranges from 1 to 2000% + * a LPAR with minimum entitlement of 0.05 per 1 virtual processor is able to "consume" 2000% CPU */ +int is_intpercent_ent (char *number) +{ + int i; + if (is_integer (number) && (i = atoi (number)) >= 1 && i <= 2000) + return TRUE; + else + return FALSE; +} + +int max_state (int a, int b) +{ + if (a == STATE_CRITICAL || b == STATE_CRITICAL) + return STATE_CRITICAL; + else if (a == STATE_WARNING || b == STATE_WARNING) + return STATE_WARNING; + else if (a == STATE_OK || b == STATE_OK) + return STATE_OK; + else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN) + return STATE_UNKNOWN; + else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT) + return STATE_DEPENDENT; + else + return max (a, b); +} + +/* get monitor status when values are higher than thresholds + * if warn or crit is 0 we assume, the value is not monitored and return STATE_OK */ +int get_status(double value, double warn, double crit) +{ + if (crit > 0 && value > crit) { + return STATE_CRITICAL; + } + if (warn > 0 && value > warn) { + return STATE_WARNING; + } + return STATE_OK; +} + +/* get monitor status when values are higher than thresholds (verbose message included) + * if warn or crit is 0 we assume, the value is not monitored and return STATE_OK */ +int get_new_status(char *verbose_message, double value, double warn, double crit) +{ + int state = STATE_OK; + + if (warn > 0 && value > warn) { + state = STATE_WARNING; + } + if (crit > 0 && value > crit) { + state = STATE_CRITICAL; + } + + if (verbose) { + printf("%s state -> %s (val=%.2f warn>%.2f crit>%.2f)\n", + verbose_message, + states[state], + value, + (warn==0?NAN:warn), /* display NAN means, values was not used for comparison */ + (crit==0?NAN:crit) + ); + } + return state; +} + +/* get monitor status when values are lower than thresholds + * if warn or crit is 0 we assume, the value is not monitored and return STATE_OK */ +int get_lower_status(double value, double warn, double crit) +{ + if (crit > 0 && value < crit) { + return STATE_CRITICAL; + } + if (warn > 0 && value < warn) { + return STATE_WARNING; + } + return STATE_OK; +} + +/* get monitor status when values are lower than thresholds (verbose message included) + * if warn or crit is 0 we assume, the value is not monitored and return STATE_OK */ +int get_new_lower_status(char *verbose_message, double value, double warn, double crit) +{ + int state = STATE_OK; + if (warn > 0 && value < warn) { + state = STATE_WARNING; + } + if (crit > 0 && value < crit) { + state = STATE_CRITICAL; + } + + if (verbose) { + printf("%s state -> %s (val=%.2f warn<%.2f crit<%.2f)\n", + verbose_message, + states[state], + value, + (warn==0?NAN:warn), /* display NAN means, values was not used for comparison */ + (crit==0?NAN:crit) + ); + } + return state; +} + +void print_version(const char *progname,const char *version) +{ + printf("%s v%s\n",progname,version); + exit(0); +} + +void print_usage (void) +{ + printf ("%s\n", _("Usage:")); + printf (" %s [ -ec=limit ] [ -ew=limit ] [ -vbw=limit ] [ -vbc=limit ] [ -i=interval ] [ -strict ] [ -h ] [ -v ] [ -V ]\n\n", progname); +} + +void print_help (void) +{ + printf ("%s %s\n",progname, version); + + printf ("Copyright (c) %s %s <%s>\n",copyright,name,email); + + printf ("%s\n", _("This plugin checks the CPU entitlement utilization on")); + printf ("%s\n", _("AIX shared processor or dedicated donating LPARs and generates an alert if")); + printf ("%s\n", _("values are out of the threshold limits")); + + printf ("\n\n"); + + print_usage (); + + + printf (" %s\n", "Entitlement monitors:"); + printf (" %s\n", "-ew, --entitlement-warning=VALUE"); + printf (" %s\n", _("Exit with WARNING status if entitlement usage is higher than VALUE")); + printf (" %s\n", "-ew, --entitlement-warning=PERCENT%"); + printf (" %s\n", _("Exit with WARNING status if entitlement usage is higher than PERCENT of")); + printf (" %s\n", _("defined entitled capacity")); + printf (" %s\n", "-ec, --entitlement-critical=VALUE"); + printf (" %s\n", _("Exit with CRITICAL status if entitlement usage is higher than VALUE")); + printf (" %s\n", "-ec, --entitlement-critical=PERCENT%"); + printf (" %s\n", _("Exit with CRITICAL status if entitlement usage is higher than PERCENT of")); + printf (" %s\n", _("defined entitled capacity")); + printf ("\n"); + printf (" %s\n", "vCPU monitors:"); + printf (" %s\n", "-vbw, --vpcu-busy-warning=PERCENT%"); + printf (" %s\n", _("Exit with WARNING status if entitlement usage is higher than PERCENT of")); + printf (" %s\n", _("available vCPU capacity")); + printf (" %s\n", "-vbc, --vpcu-busy-critical=PERCENT%"); + printf (" %s\n", _("Exit with CRITICAL status if entitlement usage is higher than PERCENT of")); + printf (" %s\n", _("available vCPU capacity")); + printf ("\n"); + + printf (" %s\n", "-i, --interval=INTEGER"); + printf (" %s\n", _("measurement interval in INTEGER seconds (1..30). Default is 1")); + printf (" %s\n", "-x, -strict, --strict"); + printf (" %s\n", _("Exit with CRITICAL status if entitlement values are obviously wrong")); + printf (" %s\n", _("e.g. entitlement usage values are 0, number of pool cpus is higher than")); + printf (" %s\n", _("installed cpus, LPAR entitlement or CPU usage is 0")); + printf (" %s\n", "-v, --verbose"); + printf (" %s\n", _("Show details for command-line debugging")); + printf (" %s\n", "-h, --help"); + printf (" %s\n", _("Print help")); + printf (" %s\n", "-V, --version"); + printf (" %s\n", _("Show plugin version")); + + + printf ("\n"); + printf ("%s\n", _("VALUE is a non-negative floating point number with 1 decimal place e.g. 3.1")); + printf ("%s\n", _("INTEGER is a positive integer number")); + printf ("%s\n", _("PERCENT is a positive integer number in the range 1..100")); + printf ("%s\n", _("PERCENT in entitlement arguments are in the range 1..2000")); + printf ("\n"); + printf ("%s\n", _("Warning and critical checks can be configured independently, critical checks")); + printf ("%s\n", _("without warnings are possible")); + printf ("%s\n", _("Exactly one PERCENT and one VALUE for each option is possible, see examples")); + printf ("\n"); + printf ("%s\n", _("Examples:")); + printf ("\n"); + printf ("%s\n", _("Checks entitlement usage at 2.0 and 2.5 or 200%:")); + printf ("%s\n", _("check_entitlement -ew 2.0 -ec 2.5 -ec 200%")); + printf ("\n"); + printf ("%s\n", _("Checks entitlement usage at 100% and 300%:")); + printf ("%s\n", _("check_entitlement -ew 100% -ec 300%")); + printf ("\n"); + + printf ("\n"); + printf ("This nagios plugin comes with ABSOLUTELY NO WARRANTY. You may redistribute\n"); + printf ("copies of the plugin under the terms of the GNU General Public License.\n"); + printf ("For more information about these matters, see the file named COPYING.\n"); + +} + +/* main */ +int main(int argc, char* argv[]) +{ + int c; + int option_index = 0; + + static struct option long_options[] = { + {"ec", required_argument, 0, 'e'}, + {"entitlement-critical", required_argument, 0, 'e'}, + {"ew", required_argument, 0, 'f'}, + {"entitlement-warning", required_argument, 0, 'f'}, + {"vbw", required_argument, 0, 'a'}, + {"virtual-busy-warning", required_argument, 0, 'a'}, + {"vbc", required_argument, 0, 'b'}, + {"virtual-busy-critical",required_argument, 0, 'b'}, + {"strict", no_argument, 0, 'x'}, + {"x", no_argument, 0, 'x'}, + {"i", required_argument, 0, 'i'}, + {"interval", required_argument, 0, 'i'}, + {"verbose", no_argument, 0, 'v'}, + {"version", no_argument, 0, 'V'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + + while (1) { + + c = getopt_long_only (argc, argv, "?Vvh", long_options, &option_index); + if (c == -1 || c == EOF) + break; + + switch (c) { + case 'V': + /* if (verbose) { printf("Option Version selected\n"); } */ + print_version(progname,version); + break; + case 'v': + verbose=TRUE; + /* if (verbose) { printf("Option verbose selected\n"); } */ + break; + case 'e': + /* if (verbose) { printf("Option entitlement-critical with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( entitlement_critical_pct != 0 ) { + printf("ERROR: -ec already set to %.0f%%! Don't specify more than once!\n",entitlement_critical_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..2000% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + entitlement_critical_pct = (double)atoi(optarg); /* pct ranges from 1 to 2000% for shared LPARs */ + /* maximum percentage is 2000% only on LPARs with minimum entitlement of 0.05 per virtual processor + * effective maximum percentage decreases when entitlement is increased, this is currently not checked for sanity */ + if ( !(is_intpercent_ent(tmp))) { + printf("ERROR: -ec %s%% out of range! Allowed 1%%..2000%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold entitlement_critical%%=%.0f%%\n",entitlement_critical_pct); } + } else { + if ( entitlement_critical != 0 ) { + printf("ERROR: -ec already set to %.1f! Don't specify more than once!\n",entitlement_critical); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int =(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + entitlement_critical=(double)tmp_int/10; + if ( !(is_positive(optarg))) { + printf("ERROR: -ec %s out of range: Entitlement has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold entitlement_critical=%.1f\n",entitlement_critical); } + } + break; + case 'f': + /* if (verbose) { printf("Option entitlement-warning with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( entitlement_warning_pct != 0 ) { + printf("ERROR: -ew already set to %.0f%%! Don't specify more than once!\n",entitlement_warning_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..2000% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + entitlement_warning_pct= (double)atoi(optarg); /* pct ranges from 1 to 2000% for shared LPARs */ + /* maximum percentage is 2000% only on LPARs with minimum entitlement of 0.05 per virtual processor + * effective maximum percentage decreases when entitlement is increased, this is currently not checked for sanity */ + if ( !(is_intpercent_ent(tmp))) { + printf("ERROR: -ew %s%% out of range! Allowed 1%%..2000%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold entitlement_warning%%=%.0f%%\n",entitlement_warning_pct); } + } else { + if ( entitlement_warning != 0 ) { + printf("ERROR: -ew already set to %.1f! Don't specify more than once!\n",entitlement_warning); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is floating value */ + int tmp_int; + tmp_int=(int)(atof(optarg)*10); /* we use only 1 digit after the comma, remove all the others */ + entitlement_warning=(double)tmp_int/10; /* we use only 1 digit after the comma, remove all the others */ + if ( !(is_positive(optarg))) { + printf("ERROR: -ew %s out of range: Entitlement has to be >0 !\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold entitlement_warning=%.1f\n",entitlement_warning); } + } + break; + case 'a': + /* if (verbose) { printf("Option vcpu-busy-warning with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( vcpu_busy_warning_pct != 0 ) { + printf("ERROR: -vbw already set to %.0f%%! Don't specify more than once!\n",vcpu_busy_warning_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + vcpu_busy_warning_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + if ( !(is_intpercent(tmp))) { + printf("ERROR: -vbw %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold vcpu_busy_warning%%=%.0f\n",vcpu_busy_warning_pct); } + } else { + /* optarg is floating value or anything else */ + printf("ERROR: -vbw %s out of range: Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + break; + case 'b': + /* if (verbose) { printf("Option vcpu-busy-critical with %s selected\n",optarg); } */ + if (strstr(optarg, "%")) { + if ( vcpu_busy_critical_pct != 0 ) { + printf("ERROR: -vbc already set to %.0f%%! Don't specify more than once!\n",vcpu_busy_critical_pct); + print_usage(); + exit(STATE_UNKNOWN); + } + /* optarg is integer 1..100% */ + char *tmp=optarg; + tmp[strlen(tmp)-1] = 0; /* remove last char assuming it's the % */ + vcpu_busy_critical_pct= (double)atoi(optarg); /* pct ranges from 1 to 100% */ + if ( !(is_intpercent(tmp))) { + printf("ERROR: -vbc %s%% out of range! Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + if (verbose) { printf("threshold vcpu_busy_critical%%=%.0f\n",vcpu_busy_critical_pct); } + } else { + /* optarg is floating value or anything else */ + printf("ERROR: -vbc %s out of range: Allowed 1%%..100%%\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + break; + case 'h': + print_help(); + exit(0); + break; + case 'i': + /* if (verbose) { printf("Option interval with %s selected\n",optarg); } */ + if ( is_intpos(optarg)) { + interval = atoi (optarg); + if ( interval > 30 ) { + printf("ERROR: Interval out of range: %s! Allowed range is 1..30!\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + } else { + printf("ERROR: Invalid value for interval: %s! Allowed range is 1..30!\n",optarg); + print_usage(); + exit(STATE_UNKNOWN); + } + break; + case 'x': + /* if (verbose) { printf("Option strict selected\n"); } */ + strict=TRUE; + break; + case '?': + print_help(); + exit(0); + break; + + } + } + + /* check if either one monitor option is used + * you can mix as many options as you want... even if it doesn't make sense at all */ + if ( entitlement_critical+ + entitlement_critical_pct+ + entitlement_warning + + entitlement_warning_pct + + vcpu_busy_warning_pct + + vcpu_busy_critical_pct == 0 ) { + printf("ERROR: Specify at least on option -ew, -ec, -vbw, -vbc!\n"); + print_usage(); + exit(STATE_UNKNOWN); + } + + /* 2 structures for difference calculation */ + perfstat_partition_total_t last_lparstats, lparstats; + + /* API variables and helpers */ + u_longlong_t last_time_base; + u_longlong_t last_pcpu_user, last_pcpu_sys, last_pcpu_idle, last_pcpu_wait; + + u_longlong_t dlt_pcpu_user, dlt_pcpu_sys, dlt_pcpu_idle, dlt_pcpu_wait; + u_longlong_t delta_time_base; + u_longlong_t delta_purr; + double phys_proc_consumed=0, entitlement=0, percent_ent=0, vcpu_busy=0; + int max_entitlement=0; + + /* retrieve the logical partition metrics */ + if (!perfstat_partition_total(NULL, &last_lparstats, sizeof(perfstat_partition_total_t), 1)) { + printf("ENTITLEMENT UNKNOWN Error getting perfstat data from perfstat_partition_total\n"); + exit(STATE_UNKNOWN); + } + + /* are we dedicated donating? */ + if(last_lparstats.type.b.donate_enabled) + dedicated_donating = 1; + + /* No entitlement and pool data on dedicated LPARs */ + if ( ! dedicated_donating && ! last_lparstats.type.b.shared_enabled ) { + printf("ENT_POOLS UNKNOWN Entitlement and pool data not available in dedicated LPAR mode\n"); + exit(STATE_UNKNOWN); + } + + sleep(interval); + + /* retrieve the logical partition metrics... again */ + if (!perfstat_partition_total(NULL, &lparstats, sizeof(perfstat_partition_total_t), 1)) { + printf("ENTITLEMENT UNKNOWN Error getting perfstat data from perfstat_partition_total\n"); + exit(STATE_UNKNOWN); + } + + /* all last_* values were set in the previous run, the deltas is what we want */ + /* physc consists of usr+sys+wait+idle */ + dlt_pcpu_user = lparstats.puser - last_lparstats.puser; + dlt_pcpu_sys = lparstats.psys - last_lparstats.psys; + dlt_pcpu_idle = lparstats.pidle - last_lparstats.pidle; + dlt_pcpu_wait = lparstats.pwait - last_lparstats.pwait; + + delta_purr = dlt_pcpu_user + dlt_pcpu_sys + dlt_pcpu_idle + dlt_pcpu_wait; + + /* get entitlement of lpar */ + entitlement = (double)lparstats.entitled_proc_capacity / 100.0 ; + + /* get number of virtual processors = maximum entitlement */ + max_entitlement = lparstats.online_cpus; + + /* new delta timer */ + delta_time_base = lparstats.timebase_last - last_lparstats.timebase_last; + + /* Physical Processor Consumed = Entitlement Consumed */ + phys_proc_consumed = (double)delta_purr / (double)delta_time_base; + + /* Percentage of Entitlement Consumed */ + percent_ent = (phys_proc_consumed / entitlement) * 100; + + /* Percentage of vCPU busy */ + vcpu_busy = (phys_proc_consumed / (double)max_entitlement) * 100; + + /* we run in shared LPAR mode? */ + if (lparstats.type.b.shared_enabled) { + + /* Compare critical and warning values */ + + /* Entitlement checks */ + /* maximum percentage is 2000% only on LPARs with minimum entitlement of 0.05 per virtual processor + * effective maximum percentage decreases when entitlement is increased, this is currently not checked for sanity */ + temp_state=get_new_status("Entitlement percentage check", percent_ent, entitlement_warning_pct, entitlement_critical_pct); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + ent_state = max_state(ent_state, temp_state); /* entitlement monitor state */ + + temp_state=get_new_status("Entitlement check", phys_proc_consumed, entitlement_warning, entitlement_critical); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + ent_state = max_state(ent_state, temp_state); /* entitlement monitor state */ + + /* vCPU busy checks */ + temp_state=get_new_status("vCPU busy percentage check",vcpu_busy, vcpu_busy_warning_pct, vcpu_busy_critical_pct); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + vcpu_busy_state = max_state(ent_state,temp_state); /* vcpu busy monitor state */ + + /* when strict checking enabled, do sanity checks too */ + if (strict) { + if ( phys_proc_consumed == 0 || + entitlement == 0 + /* more sanity checks to think about: + * phys_proc_consumed > max_entitlement + * pool_busy_time > phys_cpus_pool + * shcpu_busy_time > shcpus_in_sys */ + ) { + if (verbose) { printf("Insane performance values detected\n" ); } + ent_pool_state=STATE_CRITICAL; + } + + } + + /* human readable output */ + if ( verbose ) { + printf("\nEntitlement used: %.2f (%.2f%%), desired: %.2f, max: %.2f, vCPU busy: %6.2f%%\n", + phys_proc_consumed, + percent_ent, + entitlement, + (double)max_entitlement, + vcpu_busy + ); + + } + + printf("ENTITLEMENT %s ent_used=%.2f(%s) ent=%.2f ent_max=%d vcpu_busy=%.2f%%(%s) |ent_used=%.2f;ent=%.2f;ent_max=%d,vcpu_busy=%.2f\n", + states[ent_pool_state], + phys_proc_consumed, + states[ent_state], + entitlement, + max_entitlement, + vcpu_busy, + states[vcpu_busy_state], + phys_proc_consumed, + entitlement, + max_entitlement, + vcpu_busy + ); + + exit(ent_pool_state); + + + } + /* what to do if we're running in dedicated donating mode: + * phys_proc_consumed contains entitlement usage only if dedicated_donating is set + * if dedicated_donating is not set, this monitor doesn't make sense at all */ + + /* Dedicated LPAR with donating */ + else if ( dedicated_donating ) { + + /* Entitlement checks */ + /* the effective maximum percentage is 100% with dedicated donating, but you can still enter 2000% on the command-line + * this is currently not checked for sanity :-) */ + temp_state=get_new_status("Entitlement percentage check", percent_ent, entitlement_warning_pct, entitlement_critical_pct); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* global monitor state */ + ent_state = max_state(ent_state,temp_state); /* entitlement monitor state */ + + temp_state=get_new_status("Entitlement check", phys_proc_consumed, entitlement_warning, entitlement_critical); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* global monitor state */ + ent_state = max_state(ent_state,temp_state); /* entitlement monitor state */ + + /* vCPU busy checks */ + temp_state=get_new_status("vCPU busy percentage check", vcpu_busy, vcpu_busy_warning_pct, vcpu_busy_critical_pct); + + ent_pool_state = max_state(ent_pool_state, temp_state); /* globale monitor state */ + vcpu_busy_state = max_state(ent_state,temp_state); /* vcpu busy monitor state */ + + /* when strict checking enabled, do sanity checks too */ + if (strict) { + if ( phys_proc_consumed == 0 || + entitlement == 0 + ) { + if (verbose) { printf("Insane performance values detected\n" ); } + ent_pool_state=STATE_CRITICAL; + } + } + + /* human readable output */ + if ( verbose ) { + printf("Entitlement used: %.2f (%.2f%%), desired: %.2f, max: %.2f vCPU busy: %6.2f%%\n", + phys_proc_consumed, + percent_ent, + entitlement, + (double)max_entitlement, + vcpu_busy + ); + } + + printf("ENTITLEMENT %s ent_used=%.2f(%s) ent=%.2f ent_max=%d vcpu_busy=%.2f%% |ent_used=%.2f;ent=%.2f;ent_max=%d;vcpu_busy=%.2f\n", + states[ent_pool_state], + phys_proc_consumed, + states[ent_state], + entitlement, + max_entitlement, + vcpu_busy, + phys_proc_consumed, + entitlement, + max_entitlement, + vcpu_busy + ); + + exit(ent_pool_state); + } + + /* No action when dedicated LPAR without donating... we terminated earlier already + * just in case we get here somehow */ + printf("ENTITLEMENT UNKNOWN Unknown or unsupported LPAR mode\n"); + exit(STATE_UNKNOWN); +} + +/* This is the end. */ diff --git a/getopt_long.c b/getopt_long.c new file mode 100644 index 0000000..14cccb6 --- /dev/null +++ b/getopt_long.c @@ -0,0 +1,1237 @@ +/* + * THIS IS NOT A CLEAN COPY OF GETOPT.C AND GETOPT1.C + * -- that is, do not use it in other projects. + * + * Implementation of getopt_long, cobbled together from getopt.c and + * getopt1.c from the GNU binutils distribution. This is more-or-less + * getopt.c inserted into getopt1.c, with the definition of getopt() + * commented out. + * + * Need to ifdef out optarg, optind, opterr, optopt, to handle the + * case where these are already defined for the benefit of system + * getopt() + * + * No, it's not pretty. + */ + +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 + Free Software Foundation, Inc. + + NOTE: This source is derived from an old version taken from the GNU C + Library (glibc). + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +/*#include */ + +#ifndef HAVE_GETOPT_LONG +/* We shouldn't be compiling this module in this case, but we clearly + are (damned configuration tools!), so avoid messing up. */ + +#include "getopt_long.h" +/* See getopt_long.h for discussion of THIS_IS__STDC__ */ + + +#if !defined THIS_IS__STDC__ || !THIS_IS__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + + + +/* ******************** getopt.c ******************** */ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to drepper@gnu.org + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98 + Free Software Foundation, Inc. + + NOTE: This source is derived from an old version taken from the GNU C + Library (glibc). + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + + +#if !defined THIS_IS__STDC__ || !THIS_IS__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include +# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include +# include +#endif /* GNU C library. */ + +#ifdef VMS +# include +# if HAVE_STRING_H - 0 +# include +# endif +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +# ifdef HAVE_LIBINTL_H +# include +# define _(msgid) gettext (msgid) +# else +# define _(msgid) (msgid) +# endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + + + +/* Define HAVE_GETOPT if the getopt function (and thus, which is more + * important to us, the getopt globals, optarg, optind, opterr and + * optopt) is defined by the system. Leave undefined if they should be + * defined here instead. + */ +#ifndef HAVE_GETOPT + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = NULL; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +#endif /* #ifndef HAVE_GETOPT */ + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +# include +# define my_index strchr +#else + +# if HAVE_STRING_H +# include +# else +# if HAVE_STRINGS_H +# include +# endif +# endif + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#ifndef getenv +extern char *getenv (); +#endif + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +# if (!defined THIS_IS__STDC__ || !THIS_IS__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +# endif /* not THIS_IS__STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void +__attribute__ ((unused)) +store_args_and_env (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} +# ifdef text_set_element +text_set_element (__libc_subinit, store_args_and_env); +# endif /* text_set_element */ + +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined THIS_IS__STDC__ && THIS_IS__STDC__ +static void exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#ifdef _LIBC + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset (__mempcpy (new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined THIS_IS__STDC__ && THIS_IS__STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL + && argc == original_argc && argv == original_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +#if 0 +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +#endif +int +_getopt_internal (int argc, + char *const *argv, + const char *optstring, + const struct option *longopts, + int *longind, + int long_only) +{ + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#ifdef _LIBC +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +/* +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} +*/ + +#endif /* Not ELIDE_CODE. */ +/* ******************** ...getopt.c ******************** */ + + + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif + +/* K&R declarations!? C'mon... */ +/* Just say no to all this gymnastics */ +#if 0 +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +#endif +int getopt_long (int argc, + char *const *argv, + const char *options, + const struct option *long_options, + int *opt_index) +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +#if 0 +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +#endif +int +getopt_long_only (int argc, + char *const *argv, + const char *options, + const struct option *long_options, + int *opt_index) +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ + +#endif /* #ifndef HAVE_GETOPT_LONG */ diff --git a/getopt_long.h b/getopt_long.h new file mode 100644 index 0000000..d1ead53 --- /dev/null +++ b/getopt_long.h @@ -0,0 +1,177 @@ +/* Declarations for getopt. + Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 2000 + Free Software Foundation, Inc. + + NOTE: The canonical source of this file is maintained with the GNU C Library. + Bugs can be reported to bug-glibc@gnu.org. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +/*#include */ + +#if HAVE_UNISTD_H +/* Declares getopt, if present */ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* We're building this with a C++ compiler, essentially. Such + compilers are not required to define __STDC__, but the path we + should follow, below, is indeed that marked by __STDC__. We don't + want to force a definition of __STDC__ (though that works), because + (a) that feels bad, and (b) some compilers perfectly reasonable + complain bitterly about it. So define THIS_IS__STDC__, and replace + occurrences of __STDC__ throughout with that. + + That means that all of the occurrences of THIS_IS__STDC__ in this + file and in getopt_long.c are redundant, but I'm leaving them here + in case it becomes necessary to do cleverer things with it than + simply define it to be 1, and also as a sort of warped documentation. */ +#define THIS_IS__STDC__ 1 + +#if !HAVE_DECL_GETOPT +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +#endif /* ifndef HAVE_DECL_GETOPT */ + +#if !HAVE_DECL_GETOPT_LONG +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if defined (THIS_IS__STDC__) && THIS_IS__STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#endif /* #if !HAVE_DECL_GETOPT_LONG */ + +#if defined (THIS_IS__STDC__) && THIS_IS__STDC__ +/* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is + undefined, we haven't run the autoconf check so provide the + declaration without arguments. If it is 0, we checked and failed + to find the declaration so provide a fully prototyped one. If it + is 1, we found it so don't provide any declaration at all. */ +#if defined (__GNU_LIBRARY__) || (defined (HAVE_DECL_GETOPT) && !HAVE_DECL_GETOPT) +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +# ifndef _AIX +# if !defined (HAVE_DECL_GETOPT) +extern int getopt (); +# endif +# endif +#endif /* __GNU_LIBRARY__ */ +#if !HAVE_DECL_GETOPT_LONG +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#endif /* HAVE_DECL_GETOPT_LONG */ +#else /* not THIS_IS__STDC__ */ +#if !HAVE_DECL_GETOPT +extern int getopt (); +#endif /* HAVE_DECL_GETOPT */ +#if !HAVE_DECL_GETOPT_LONG +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* HAVE_DECL_GETOPT_LONG */ +#endif /* THIS_IS__STDC__ */ + + +#ifdef __cplusplus +} +#endif + +#endif /* getopt.h */