Back to index

nagios-plugins  1.4.16
getloadavg.c
Go to the documentation of this file.
00001 /* Get the system load averages.
00002 
00003    Copyright (C) 1985-1989, 1991-1995, 1997, 1999-2000, 2003-2010 Free Software
00004    Foundation, Inc.
00005 
00006    NOTE: The canonical source of this file is maintained with gnulib.
00007    Bugs can be reported to bug-gnulib@gnu.org.
00008 
00009    This program is free software: you can redistribute it and/or modify
00010    it under the terms of the GNU General Public License as published by
00011    the Free Software Foundation; either version 3 of the License, or
00012    (at your option) any later version.
00013 
00014    This program is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017    GNU General Public License for more details.
00018 
00019    You should have received a copy of the GNU General Public License
00020    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00021 
00022 /* Compile-time symbols that this file uses:
00023 
00024    HAVE_PSTAT_GETDYNAMIC        Define this if your system has the
00025                                 pstat_getdynamic function.  I think it
00026                                 is unique to HPUX9.  The best way to get the
00027                                 definition is through the AC_FUNC_GETLOADAVG
00028                                 macro that comes with autoconf 2.13 or newer.
00029                                 If that isn't an option, then just put
00030                                 AC_CHECK_FUNCS(pstat_getdynamic) in your
00031                                 configure.in file.
00032    HAVE_LIBPERFSTAT Define this if your system has the
00033                                 perfstat_cpu_total function in libperfstat (AIX).
00034    FIXUP_KERNEL_SYMBOL_ADDR()   Adjust address in returned struct nlist.
00035    KERNEL_FILE                  Name of the kernel file to nlist.
00036    LDAV_CVT()                   Scale the load average from the kernel.
00037                                 Returns a double.
00038    LDAV_SYMBOL                  Name of kernel symbol giving load average.
00039    LOAD_AVE_TYPE                Type of the load average array in the kernel.
00040                                 Must be defined unless one of
00041                                 apollo, DGUX, NeXT, or UMAX is defined;
00042                                 or we have libkstat;
00043                                 otherwise, no load average is available.
00044    HAVE_NLIST_H                 nlist.h is available.  NLIST_STRUCT defaults
00045                                 to this.
00046    NLIST_STRUCT                 Include nlist.h, not a.out.h.
00047    N_NAME_POINTER               The nlist n_name element is a pointer,
00048                                 not an array.
00049    HAVE_STRUCT_NLIST_N_UN_N_NAME `n_un.n_name' is member of `struct nlist'.
00050    LINUX_LDAV_FILE              [__linux__, __CYGWIN__]: File containing
00051                                 load averages.
00052 
00053    Specific system predefines this file uses, aside from setting
00054    default values if not emacs:
00055 
00056    apollo
00057    BSD                          Real BSD, not just BSD-like.
00058    convex
00059    DGUX
00060    eunice                       UNIX emulator under VMS.
00061    hpux
00062    __MSDOS__                    No-op for MSDOS.
00063    NeXT
00064    sgi
00065    sequent                      Sequent Dynix 3.x.x (BSD)
00066    _SEQUENT_                    Sequent DYNIX/ptx 1.x.x (SYSV)
00067    sony_news                    NEWS-OS (works at least for 4.1C)
00068    UMAX
00069    UMAX4_3
00070    VMS
00071    WINDOWS32                    No-op for Windows95/NT.
00072    __linux__                    Linux: assumes /proc file system mounted.
00073                                 Support from Michael K. Johnson.
00074    __CYGWIN__                   Cygwin emulates linux /proc/loadavg.
00075    __NetBSD__                   NetBSD: assumes /kern file system mounted.
00076 
00077    In addition, to avoid nesting many #ifdefs, we internally set
00078    LDAV_DONE to indicate that the load average has been computed.
00079 
00080    We also #define LDAV_PRIVILEGED if a program will require
00081    special installation to be able to call getloadavg.  */
00082 
00083 /* "configure" defines CONFIGURING_GETLOADAVG to sidestep problems
00084    with partially-configured source directories.  */
00085 
00086 #ifndef CONFIGURING_GETLOADAVG
00087 # include <config.h>
00088 # include <stdbool.h>
00089 #endif
00090 
00091 /* Specification.  */
00092 #include <stdlib.h>
00093 
00094 #include <errno.h>
00095 #include <stdio.h>
00096 
00097 /* Exclude all the code except the test program at the end
00098    if the system has its own `getloadavg' function.  */
00099 
00100 #ifndef HAVE_GETLOADAVG
00101 
00102 # include <sys/types.h>
00103 
00104 /* Both the Emacs and non-Emacs sections want this.  Some
00105    configuration files' definitions for the LOAD_AVE_CVT macro (like
00106    sparc.h's) use macros like FSCALE, defined here.  */
00107 # if defined (unix) || defined (__unix)
00108 #  include <sys/param.h>
00109 # endif
00110 
00111 # include "c-strtod.h"
00112 # include "cloexec.h"
00113 # include "intprops.h"
00114 
00115 /* The existing Emacs configuration files define a macro called
00116    LOAD_AVE_CVT, which accepts a value of type LOAD_AVE_TYPE, and
00117    returns the load average multiplied by 100.  What we actually want
00118    is a macro called LDAV_CVT, which returns the load average as an
00119    unmultiplied double.
00120 
00121    For backwards compatibility, we'll define LDAV_CVT in terms of
00122    LOAD_AVE_CVT, but future machine config files should just define
00123    LDAV_CVT directly.  */
00124 
00125 # if !defined (LDAV_CVT) && defined (LOAD_AVE_CVT)
00126 #  define LDAV_CVT(n) (LOAD_AVE_CVT (n) / 100.0)
00127 # endif
00128 
00129 # if !defined (BSD) && defined (ultrix)
00130 /* Ultrix behaves like BSD on Vaxen.  */
00131 #  define BSD
00132 # endif
00133 
00134 # ifdef NeXT
00135 /* NeXT in the 2.{0,1,2} releases defines BSD in <sys/param.h>, which
00136    conflicts with the definition understood in this file, that this
00137    really is BSD. */
00138 #  undef BSD
00139 
00140 /* NeXT defines FSCALE in <sys/param.h>.  However, we take FSCALE being
00141    defined to mean that the nlist method should be used, which is not true.  */
00142 #  undef FSCALE
00143 # endif
00144 
00145 /* Same issues as for NeXT apply to the HURD-based GNU system.  */
00146 # ifdef __GNU__
00147 #  undef BSD
00148 #  undef FSCALE
00149 # endif /* __GNU__ */
00150 
00151 /* Set values that are different from the defaults, which are
00152    set a little farther down with #ifndef.  */
00153 
00154 
00155 /* Some shorthands.  */
00156 
00157 # if defined (HPUX) && !defined (hpux)
00158 #  define hpux
00159 # endif
00160 
00161 # if defined (__hpux) && !defined (hpux)
00162 #  define hpux
00163 # endif
00164 
00165 # if defined (__sun) && !defined (sun)
00166 #  define sun
00167 # endif
00168 
00169 # if defined (hp300) && !defined (hpux)
00170 #  define MORE_BSD
00171 # endif
00172 
00173 # if defined (ultrix) && defined (mips)
00174 #  define decstation
00175 # endif
00176 
00177 # if defined (__SVR4) && !defined (SVR4)
00178 #  define SVR4
00179 # endif
00180 
00181 # if (defined (sun) && defined (SVR4)) || defined (SOLARIS2)
00182 #  define SUNOS_5
00183 # endif
00184 
00185 # if defined (__osf__) && (defined (__alpha) || defined (__alpha__))
00186 #  define OSF_ALPHA
00187 #  include <sys/mbuf.h>
00188 #  include <sys/socket.h>
00189 #  include <net/route.h>
00190 #  include <sys/table.h>
00191 /* Tru64 4.0D's table.h redefines sys */
00192 #  undef sys
00193 # endif
00194 
00195 # if defined (__osf__) && (defined (mips) || defined (__mips__))
00196 #  define OSF_MIPS
00197 #  include <sys/table.h>
00198 # endif
00199 
00200 /* UTek's /bin/cc on the 4300 has no architecture specific cpp define by
00201    default, but _MACH_IND_SYS_TYPES is defined in <sys/types.h>.  Combine
00202    that with a couple of other things and we'll have a unique match.  */
00203 # if !defined (tek4300) && defined (unix) && defined (m68k) && defined (mc68000) && defined (mc68020) && defined (_MACH_IND_SYS_TYPES)
00204 #  define tek4300                       /* Define by emacs, but not by other users.  */
00205 # endif
00206 
00207 
00208 /* VAX C can't handle multi-line #ifs, or lines longer than 256 chars.  */
00209 # ifndef LOAD_AVE_TYPE
00210 
00211 #  ifdef MORE_BSD
00212 #   define LOAD_AVE_TYPE long
00213 #  endif
00214 
00215 #  ifdef sun
00216 #   define LOAD_AVE_TYPE long
00217 #  endif
00218 
00219 #  ifdef decstation
00220 #   define LOAD_AVE_TYPE long
00221 #  endif
00222 
00223 #  ifdef _SEQUENT_
00224 #   define LOAD_AVE_TYPE long
00225 #  endif
00226 
00227 #  ifdef sgi
00228 #   define LOAD_AVE_TYPE long
00229 #  endif
00230 
00231 #  ifdef SVR4
00232 #   define LOAD_AVE_TYPE long
00233 #  endif
00234 
00235 #  ifdef sony_news
00236 #   define LOAD_AVE_TYPE long
00237 #  endif
00238 
00239 #  ifdef sequent
00240 #   define LOAD_AVE_TYPE long
00241 #  endif
00242 
00243 #  ifdef OSF_ALPHA
00244 #   define LOAD_AVE_TYPE long
00245 #  endif
00246 
00247 #  if defined (ardent) && defined (titan)
00248 #   define LOAD_AVE_TYPE long
00249 #  endif
00250 
00251 #  ifdef tek4300
00252 #   define LOAD_AVE_TYPE long
00253 #  endif
00254 
00255 #  if defined (alliant) && defined (i860) /* Alliant FX/2800 */
00256 #   define LOAD_AVE_TYPE long
00257 #  endif
00258 
00259 #  if defined _AIX && ! defined HAVE_LIBPERFSTAT
00260 #   define LOAD_AVE_TYPE long
00261 #  endif
00262 
00263 #  ifdef convex
00264 #   define LOAD_AVE_TYPE double
00265 #   ifndef LDAV_CVT
00266 #    define LDAV_CVT(n) (n)
00267 #   endif
00268 #  endif
00269 
00270 # endif /* No LOAD_AVE_TYPE.  */
00271 
00272 # ifdef OSF_ALPHA
00273 /* <sys/param.h> defines an incorrect value for FSCALE on Alpha OSF/1,
00274    according to ghazi@noc.rutgers.edu.  */
00275 #  undef FSCALE
00276 #  define FSCALE 1024.0
00277 # endif
00278 
00279 # if defined (alliant) && defined (i860) /* Alliant FX/2800 */
00280 /* <sys/param.h> defines an incorrect value for FSCALE on an
00281    Alliant FX/2800 Concentrix 2.2, according to ghazi@noc.rutgers.edu.  */
00282 #  undef FSCALE
00283 #  define FSCALE 100.0
00284 # endif
00285 
00286 
00287 # ifndef FSCALE
00288 
00289 /* SunOS and some others define FSCALE in sys/param.h.  */
00290 
00291 #  ifdef MORE_BSD
00292 #   define FSCALE 2048.0
00293 #  endif
00294 
00295 #  if defined (MIPS) || defined (SVR4) || defined (decstation)
00296 #   define FSCALE 256
00297 #  endif
00298 
00299 #  if defined (sgi) || defined (sequent)
00300 /* Sometimes both MIPS and sgi are defined, so FSCALE was just defined
00301    above under #ifdef MIPS.  But we want the sgi value.  */
00302 #   undef FSCALE
00303 #   define FSCALE 1000.0
00304 #  endif
00305 
00306 #  if defined (ardent) && defined (titan)
00307 #   define FSCALE 65536.0
00308 #  endif
00309 
00310 #  ifdef tek4300
00311 #   define FSCALE 100.0
00312 #  endif
00313 
00314 #  if defined _AIX && !defined HAVE_LIBPERFSTAT
00315 #   define FSCALE 65536.0
00316 #  endif
00317 
00318 # endif /* Not FSCALE.  */
00319 
00320 # if !defined (LDAV_CVT) && defined (FSCALE)
00321 #  define LDAV_CVT(n) (((double) (n)) / FSCALE)
00322 # endif
00323 
00324 # ifndef NLIST_STRUCT
00325 #  if HAVE_NLIST_H
00326 #   define NLIST_STRUCT
00327 #  endif
00328 # endif
00329 
00330 # if defined (sgi) || (defined (mips) && !defined (BSD))
00331 #  define FIXUP_KERNEL_SYMBOL_ADDR(nl) ((nl)[0].n_value &= ~(1 << 31))
00332 # endif
00333 
00334 
00335 # if !defined (KERNEL_FILE) && defined (sequent)
00336 #  define KERNEL_FILE "/dynix"
00337 # endif
00338 
00339 # if !defined (KERNEL_FILE) && defined (hpux)
00340 #  define KERNEL_FILE "/hp-ux"
00341 # endif
00342 
00343 # if !defined (KERNEL_FILE) && (defined (_SEQUENT_) || defined (MIPS) || defined (SVR4) || defined (ISC) || defined (sgi) || (defined (ardent) && defined (titan)))
00344 #  define KERNEL_FILE "/unix"
00345 # endif
00346 
00347 
00348 # if !defined (LDAV_SYMBOL) && defined (alliant)
00349 #  define LDAV_SYMBOL "_Loadavg"
00350 # endif
00351 
00352 # if !defined (LDAV_SYMBOL) && ((defined (hpux) && !defined (hp9000s300)) || defined (_SEQUENT_) || defined (SVR4) || defined (ISC) || defined (sgi) || (defined (ardent) && defined (titan)) || (defined (_AIX) && !defined(HAVE_LIBPERFSTAT)))
00353 #  define LDAV_SYMBOL "avenrun"
00354 # endif
00355 
00356 # include <unistd.h>
00357 
00358 /* LOAD_AVE_TYPE should only get defined if we're going to use the
00359    nlist method.  */
00360 # if !defined (LOAD_AVE_TYPE) && (defined (BSD) || defined (LDAV_CVT) || defined (KERNEL_FILE) || defined (LDAV_SYMBOL))
00361 #  define LOAD_AVE_TYPE double
00362 # endif
00363 
00364 # ifdef LOAD_AVE_TYPE
00365 
00366 #  ifndef __VMS
00367 #   ifndef __linux__
00368 #    ifndef NLIST_STRUCT
00369 #     include <a.out.h>
00370 #    else /* NLIST_STRUCT */
00371 #     include <nlist.h>
00372 #    endif /* NLIST_STRUCT */
00373 
00374 #    ifdef SUNOS_5
00375 #     include <fcntl.h>
00376 #     include <kvm.h>
00377 #     include <kstat.h>
00378 #    endif
00379 
00380 #    if defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC)
00381 #     include <sys/pstat.h>
00382 #    endif
00383 
00384 #    ifndef KERNEL_FILE
00385 #     define KERNEL_FILE "/vmunix"
00386 #    endif /* KERNEL_FILE */
00387 
00388 #    ifndef LDAV_SYMBOL
00389 #     define LDAV_SYMBOL "_avenrun"
00390 #    endif /* LDAV_SYMBOL */
00391 #   endif /* __linux__ */
00392 
00393 #  else /* __VMS */
00394 
00395 #   ifndef eunice
00396 #    include <iodef.h>
00397 #    include <descrip.h>
00398 #   else /* eunice */
00399 #    include <vms/iodef.h>
00400 #   endif /* eunice */
00401 #  endif /* __VMS */
00402 
00403 #  ifndef LDAV_CVT
00404 #   define LDAV_CVT(n) ((double) (n))
00405 #  endif /* !LDAV_CVT */
00406 
00407 # endif /* LOAD_AVE_TYPE */
00408 
00409 # if defined HAVE_LIBPERFSTAT
00410 #  include <sys/protosw.h>
00411 #  include <libperfstat.h>
00412 #  include <sys/proc.h>
00413 #  ifndef SBITS
00414 #   define SBITS 16
00415 #  endif
00416 # endif
00417 
00418 # if defined (__GNU__) && !defined (NeXT)
00419 /* Note that NeXT Openstep defines __GNU__ even though it should not.  */
00420 /* GNU system acts much like NeXT, for load average purposes,
00421    but not exactly.  */
00422 #  define NeXT
00423 #  define host_self mach_host_self
00424 # endif
00425 
00426 # ifdef NeXT
00427 #  ifdef HAVE_MACH_MACH_H
00428 #   include <mach/mach.h>
00429 #  else
00430 #   include <mach.h>
00431 #  endif
00432 # endif /* NeXT */
00433 
00434 # ifdef sgi
00435 #  include <sys/sysmp.h>
00436 # endif /* sgi */
00437 
00438 # ifdef UMAX
00439 #  include <signal.h>
00440 #  include <sys/time.h>
00441 #  include <sys/wait.h>
00442 #  include <sys/syscall.h>
00443 
00444 #  ifdef UMAX_43
00445 #   include <machine/cpu.h>
00446 #   include <inq_stats/statistics.h>
00447 #   include <inq_stats/sysstats.h>
00448 #   include <inq_stats/cpustats.h>
00449 #   include <inq_stats/procstats.h>
00450 #  else /* Not UMAX_43.  */
00451 #   include <sys/sysdefs.h>
00452 #   include <sys/statistics.h>
00453 #   include <sys/sysstats.h>
00454 #   include <sys/cpudefs.h>
00455 #   include <sys/cpustats.h>
00456 #   include <sys/procstats.h>
00457 #  endif /* Not UMAX_43.  */
00458 # endif /* UMAX */
00459 
00460 # ifdef DGUX
00461 #  include <sys/dg_sys_info.h>
00462 # endif
00463 
00464 # include "fcntl--.h"
00465 
00466 /* Avoid static vars inside a function since in HPUX they dump as pure.  */
00467 
00468 # ifdef NeXT
00469 static processor_set_t default_set;
00470 static bool getloadavg_initialized;
00471 # endif /* NeXT */
00472 
00473 # ifdef UMAX
00474 static unsigned int cpus = 0;
00475 static unsigned int samples;
00476 # endif /* UMAX */
00477 
00478 # ifdef DGUX
00479 static struct dg_sys_info_load_info load_info;  /* what-a-mouthful! */
00480 # endif /* DGUX */
00481 
00482 # if !defined (HAVE_LIBKSTAT) && defined (LOAD_AVE_TYPE)
00483 /* File descriptor open to /dev/kmem or VMS load ave driver.  */
00484 static int channel;
00485 /* True iff channel is valid.  */
00486 static bool getloadavg_initialized;
00487 /* Offset in kmem to seek to read load average, or 0 means invalid.  */
00488 static long offset;
00489 
00490 #  if ! defined __VMS && ! defined sgi && ! defined __linux__
00491 static struct nlist nl[2];
00492 #  endif
00493 
00494 #  ifdef SUNOS_5
00495 static kvm_t *kd;
00496 #  endif /* SUNOS_5 */
00497 
00498 # endif /* LOAD_AVE_TYPE && !HAVE_LIBKSTAT */
00499 
00500 /* Put the 1 minute, 5 minute and 15 minute load averages
00501    into the first NELEM elements of LOADAVG.
00502    Return the number written (never more than 3, but may be less than NELEM),
00503    or -1 if an error occurred.  */
00504 
00505 int
00506 getloadavg (double loadavg[], int nelem)
00507 {
00508   int elem = 0;                 /* Return value.  */
00509 
00510 # ifdef NO_GET_LOAD_AVG
00511 #  define LDAV_DONE
00512   /* Set errno to zero to indicate that there was no particular error;
00513      this function just can't work at all on this system.  */
00514   errno = 0;
00515   elem = -1;
00516 # endif
00517 
00518 # if !defined (LDAV_DONE) && defined (HAVE_LIBKSTAT)
00519 /* Use libkstat because we don't have to be root.  */
00520 #  define LDAV_DONE
00521   kstat_ctl_t *kc;
00522   kstat_t *ksp;
00523   kstat_named_t *kn;
00524 
00525   kc = kstat_open ();
00526   if (kc == 0)
00527     return -1;
00528   ksp = kstat_lookup (kc, "unix", 0, "system_misc");
00529   if (ksp == 0)
00530     return -1;
00531   if (kstat_read (kc, ksp, 0) == -1)
00532     return -1;
00533 
00534 
00535   kn = kstat_data_lookup (ksp, "avenrun_1min");
00536   if (kn == 0)
00537     {
00538       /* Return -1 if no load average information is available.  */
00539       nelem = 0;
00540       elem = -1;
00541     }
00542 
00543   if (nelem >= 1)
00544     loadavg[elem++] = (double) kn->value.ul / FSCALE;
00545 
00546   if (nelem >= 2)
00547     {
00548       kn = kstat_data_lookup (ksp, "avenrun_5min");
00549       if (kn != 0)
00550         {
00551           loadavg[elem++] = (double) kn->value.ul / FSCALE;
00552 
00553           if (nelem >= 3)
00554             {
00555               kn = kstat_data_lookup (ksp, "avenrun_15min");
00556               if (kn != 0)
00557                 loadavg[elem++] = (double) kn->value.ul / FSCALE;
00558             }
00559         }
00560     }
00561 
00562   kstat_close (kc);
00563 # endif /* HAVE_LIBKSTAT */
00564 
00565 # if !defined (LDAV_DONE) && defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC)
00566 /* Use pstat_getdynamic() because we don't have to be root.  */
00567 #  define LDAV_DONE
00568 #  undef LOAD_AVE_TYPE
00569 
00570   struct pst_dynamic dyn_info;
00571   if (pstat_getdynamic (&dyn_info, sizeof (dyn_info), 0, 0) < 0)
00572     return -1;
00573   if (nelem > 0)
00574     loadavg[elem++] = dyn_info.psd_avg_1_min;
00575   if (nelem > 1)
00576     loadavg[elem++] = dyn_info.psd_avg_5_min;
00577   if (nelem > 2)
00578     loadavg[elem++] = dyn_info.psd_avg_15_min;
00579 
00580 # endif /* hpux && HAVE_PSTAT_GETDYNAMIC */
00581 
00582 # if ! defined LDAV_DONE && defined HAVE_LIBPERFSTAT
00583 #  define LDAV_DONE
00584 #  undef LOAD_AVE_TYPE
00585 /* Use perfstat_cpu_total because we don't have to be root. */
00586   {
00587     perfstat_cpu_total_t cpu_stats;
00588     int result = perfstat_cpu_total (NULL, &cpu_stats, sizeof cpu_stats, 1);
00589     if (result == -1)
00590       return result;
00591     loadavg[0] = cpu_stats.loadavg[0] / (double)(1 << SBITS);
00592     loadavg[1] = cpu_stats.loadavg[1] / (double)(1 << SBITS);
00593     loadavg[2] = cpu_stats.loadavg[2] / (double)(1 << SBITS);
00594     elem = 3;
00595   }
00596 # endif
00597 
00598 # if !defined (LDAV_DONE) && (defined (__linux__) || defined (__CYGWIN__))
00599 #  define LDAV_DONE
00600 #  undef LOAD_AVE_TYPE
00601 
00602 #  ifndef LINUX_LDAV_FILE
00603 #   define LINUX_LDAV_FILE "/proc/loadavg"
00604 #  endif
00605 
00606   char ldavgbuf[3 * (INT_STRLEN_BOUND (int) + sizeof ".00 ")];
00607   char const *ptr = ldavgbuf;
00608   int fd, count;
00609 
00610   fd = open (LINUX_LDAV_FILE, O_RDONLY);
00611   if (fd == -1)
00612     return -1;
00613   count = read (fd, ldavgbuf, sizeof ldavgbuf - 1);
00614   (void) close (fd);
00615   if (count <= 0)
00616     return -1;
00617   ldavgbuf[count] = '\0';
00618 
00619   for (elem = 0; elem < nelem; elem++)
00620     {
00621       char *endptr;
00622       double d;
00623 
00624       errno = 0;
00625       d = c_strtod (ptr, &endptr);
00626       if (ptr == endptr || (d == 0 && errno != 0))
00627         {
00628           if (elem == 0)
00629             return -1;
00630           break;
00631         }
00632       loadavg[elem] = d;
00633       ptr = endptr;
00634     }
00635 
00636   return elem;
00637 
00638 # endif /* __linux__ || __CYGWIN__ */
00639 
00640 # if !defined (LDAV_DONE) && defined (__NetBSD__)
00641 #  define LDAV_DONE
00642 #  undef LOAD_AVE_TYPE
00643 
00644 #  ifndef NETBSD_LDAV_FILE
00645 #   define NETBSD_LDAV_FILE "/kern/loadavg"
00646 #  endif
00647 
00648   unsigned long int load_ave[3], scale;
00649   int count;
00650   FILE *fp;
00651 
00652   fp = fopen (NETBSD_LDAV_FILE, "r");
00653   if (fp == NULL)
00654     return -1;
00655   count = fscanf (fp, "%lu %lu %lu %lu\n",
00656                   &load_ave[0], &load_ave[1], &load_ave[2],
00657                   &scale);
00658   (void) fclose (fp);
00659   if (count != 4)
00660     return -1;
00661 
00662   for (elem = 0; elem < nelem; elem++)
00663     loadavg[elem] = (double) load_ave[elem] / (double) scale;
00664 
00665   return elem;
00666 
00667 # endif /* __NetBSD__ */
00668 
00669 # if !defined (LDAV_DONE) && defined (NeXT)
00670 #  define LDAV_DONE
00671   /* The NeXT code was adapted from iscreen 3.2.  */
00672 
00673   host_t host;
00674   struct processor_set_basic_info info;
00675   unsigned int info_count;
00676 
00677   /* We only know how to get the 1-minute average for this system,
00678      so even if the caller asks for more than 1, we only return 1.  */
00679 
00680   if (!getloadavg_initialized)
00681     {
00682       if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS)
00683         getloadavg_initialized = true;
00684     }
00685 
00686   if (getloadavg_initialized)
00687     {
00688       info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
00689       if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
00690                               (processor_set_info_t) &info, &info_count)
00691           != KERN_SUCCESS)
00692         getloadavg_initialized = false;
00693       else
00694         {
00695           if (nelem > 0)
00696             loadavg[elem++] = (double) info.load_average / LOAD_SCALE;
00697         }
00698     }
00699 
00700   if (!getloadavg_initialized)
00701     return -1;
00702 # endif /* NeXT */
00703 
00704 # if !defined (LDAV_DONE) && defined (UMAX)
00705 #  define LDAV_DONE
00706 /* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
00707    have a /dev/kmem.  Information about the workings of the running kernel
00708    can be gathered with inq_stats system calls.
00709    We only know how to get the 1-minute average for this system.  */
00710 
00711   struct proc_summary proc_sum_data;
00712   struct stat_descr proc_info;
00713   double load;
00714   register unsigned int i, j;
00715 
00716   if (cpus == 0)
00717     {
00718       register unsigned int c, i;
00719       struct cpu_config conf;
00720       struct stat_descr desc;
00721 
00722       desc.sd_next = 0;
00723       desc.sd_subsys = SUBSYS_CPU;
00724       desc.sd_type = CPUTYPE_CONFIG;
00725       desc.sd_addr = (char *) &conf;
00726       desc.sd_size = sizeof conf;
00727 
00728       if (inq_stats (1, &desc))
00729         return -1;
00730 
00731       c = 0;
00732       for (i = 0; i < conf.config_maxclass; ++i)
00733         {
00734           struct class_stats stats;
00735           bzero ((char *) &stats, sizeof stats);
00736 
00737           desc.sd_type = CPUTYPE_CLASS;
00738           desc.sd_objid = i;
00739           desc.sd_addr = (char *) &stats;
00740           desc.sd_size = sizeof stats;
00741 
00742           if (inq_stats (1, &desc))
00743             return -1;
00744 
00745           c += stats.class_numcpus;
00746         }
00747       cpus = c;
00748       samples = cpus < 2 ? 3 : (2 * cpus / 3);
00749     }
00750 
00751   proc_info.sd_next = 0;
00752   proc_info.sd_subsys = SUBSYS_PROC;
00753   proc_info.sd_type = PROCTYPE_SUMMARY;
00754   proc_info.sd_addr = (char *) &proc_sum_data;
00755   proc_info.sd_size = sizeof (struct proc_summary);
00756   proc_info.sd_sizeused = 0;
00757 
00758   if (inq_stats (1, &proc_info) != 0)
00759     return -1;
00760 
00761   load = proc_sum_data.ps_nrunnable;
00762   j = 0;
00763   for (i = samples - 1; i > 0; --i)
00764     {
00765       load += proc_sum_data.ps_nrun[j];
00766       if (j++ == PS_NRUNSIZE)
00767         j = 0;
00768     }
00769 
00770   if (nelem > 0)
00771     loadavg[elem++] = load / samples / cpus;
00772 # endif /* UMAX */
00773 
00774 # if !defined (LDAV_DONE) && defined (DGUX)
00775 #  define LDAV_DONE
00776   /* This call can return -1 for an error, but with good args
00777      it's not supposed to fail.  The first argument is for no
00778      apparent reason of type `long int *'.  */
00779   dg_sys_info ((long int *) &load_info,
00780                DG_SYS_INFO_LOAD_INFO_TYPE,
00781                DG_SYS_INFO_LOAD_VERSION_0);
00782 
00783   if (nelem > 0)
00784     loadavg[elem++] = load_info.one_minute;
00785   if (nelem > 1)
00786     loadavg[elem++] = load_info.five_minute;
00787   if (nelem > 2)
00788     loadavg[elem++] = load_info.fifteen_minute;
00789 # endif /* DGUX */
00790 
00791 # if !defined (LDAV_DONE) && defined (apollo)
00792 #  define LDAV_DONE
00793 /* Apollo code from lisch@mentorg.com (Ray Lischner).
00794 
00795    This system call is not documented.  The load average is obtained as
00796    three long integers, for the load average over the past minute,
00797    five minutes, and fifteen minutes.  Each value is a scaled integer,
00798    with 16 bits of integer part and 16 bits of fraction part.
00799 
00800    I'm not sure which operating system first supported this system call,
00801    but I know that SR10.2 supports it.  */
00802 
00803   extern void proc1_$get_loadav ();
00804   unsigned long load_ave[3];
00805 
00806   proc1_$get_loadav (load_ave);
00807 
00808   if (nelem > 0)
00809     loadavg[elem++] = load_ave[0] / 65536.0;
00810   if (nelem > 1)
00811     loadavg[elem++] = load_ave[1] / 65536.0;
00812   if (nelem > 2)
00813     loadavg[elem++] = load_ave[2] / 65536.0;
00814 # endif /* apollo */
00815 
00816 # if !defined (LDAV_DONE) && defined (OSF_MIPS)
00817 #  define LDAV_DONE
00818 
00819   struct tbl_loadavg load_ave;
00820   table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
00821   loadavg[elem++]
00822     = (load_ave.tl_lscale == 0
00823        ? load_ave.tl_avenrun.d[0]
00824        : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale));
00825 # endif /* OSF_MIPS */
00826 
00827 # if !defined (LDAV_DONE) && (defined (__MSDOS__) || defined (WINDOWS32))
00828 #  define LDAV_DONE
00829 
00830   /* A faithful emulation is going to have to be saved for a rainy day.  */
00831   for ( ; elem < nelem; elem++)
00832     {
00833       loadavg[elem] = 0.0;
00834     }
00835 # endif  /* __MSDOS__ || WINDOWS32 */
00836 
00837 # if !defined (LDAV_DONE) && defined (OSF_ALPHA)
00838 #  define LDAV_DONE
00839 
00840   struct tbl_loadavg load_ave;
00841   table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
00842   for (elem = 0; elem < nelem; elem++)
00843     loadavg[elem]
00844       = (load_ave.tl_lscale == 0
00845          ? load_ave.tl_avenrun.d[elem]
00846          : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
00847 # endif /* OSF_ALPHA */
00848 
00849 # if ! defined LDAV_DONE && defined __VMS
00850   /* VMS specific code -- read from the Load Ave driver.  */
00851 
00852   LOAD_AVE_TYPE load_ave[3];
00853   static bool getloadavg_initialized;
00854 #  ifdef eunice
00855   struct
00856   {
00857     int dsc$w_length;
00858     char *dsc$a_pointer;
00859   } descriptor;
00860 #  endif
00861 
00862   /* Ensure that there is a channel open to the load ave device.  */
00863   if (!getloadavg_initialized)
00864     {
00865       /* Attempt to open the channel.  */
00866 #  ifdef eunice
00867       descriptor.dsc$w_length = 18;
00868       descriptor.dsc$a_pointer = "$$VMS_LOAD_AVERAGE";
00869 #  else
00870       $DESCRIPTOR (descriptor, "LAV0:");
00871 #  endif
00872       if (sys$assign (&descriptor, &channel, 0, 0) & 1)
00873         getloadavg_initialized = true;
00874     }
00875 
00876   /* Read the load average vector.  */
00877   if (getloadavg_initialized
00878       && !(sys$qiow (0, channel, IO$_READVBLK, 0, 0, 0,
00879                      load_ave, 12, 0, 0, 0, 0) & 1))
00880     {
00881       sys$dassgn (channel);
00882       getloadavg_initialized = false;
00883     }
00884 
00885   if (!getloadavg_initialized)
00886     return -1;
00887 # endif /* ! defined LDAV_DONE && defined __VMS */
00888 
00889 # if ! defined LDAV_DONE && defined LOAD_AVE_TYPE && ! defined __VMS
00890 
00891   /* UNIX-specific code -- read the average from /dev/kmem.  */
00892 
00893 #  define LDAV_PRIVILEGED               /* This code requires special installation.  */
00894 
00895   LOAD_AVE_TYPE load_ave[3];
00896 
00897   /* Get the address of LDAV_SYMBOL.  */
00898   if (offset == 0)
00899     {
00900 #  ifndef sgi
00901 #   if ! defined NLIST_STRUCT || ! defined N_NAME_POINTER
00902       strcpy (nl[0].n_name, LDAV_SYMBOL);
00903       strcpy (nl[1].n_name, "");
00904 #   else /* NLIST_STRUCT */
00905 #    ifdef HAVE_STRUCT_NLIST_N_UN_N_NAME
00906       nl[0].n_un.n_name = LDAV_SYMBOL;
00907       nl[1].n_un.n_name = 0;
00908 #    else /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */
00909       nl[0].n_name = LDAV_SYMBOL;
00910       nl[1].n_name = 0;
00911 #    endif /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */
00912 #   endif /* NLIST_STRUCT */
00913 
00914 #   ifndef SUNOS_5
00915       if (
00916 #    if !(defined (_AIX) && !defined (ps2))
00917           nlist (KERNEL_FILE, nl)
00918 #    else  /* _AIX */
00919           knlist (nl, 1, sizeof (nl[0]))
00920 #    endif
00921           >= 0)
00922           /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i.  */
00923           {
00924 #    ifdef FIXUP_KERNEL_SYMBOL_ADDR
00925             FIXUP_KERNEL_SYMBOL_ADDR (nl);
00926 #    endif
00927             offset = nl[0].n_value;
00928           }
00929 #   endif /* !SUNOS_5 */
00930 #  else  /* sgi */
00931       int ldav_off;
00932 
00933       ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
00934       if (ldav_off != -1)
00935         offset = (long int) ldav_off & 0x7fffffff;
00936 #  endif /* sgi */
00937     }
00938 
00939   /* Make sure we have /dev/kmem open.  */
00940   if (!getloadavg_initialized)
00941     {
00942 #  ifndef SUNOS_5
00943       channel = open ("/dev/kmem", O_RDONLY);
00944       if (channel >= 0)
00945         {
00946           /* Set the channel to close on exec, so it does not
00947              litter any child's descriptor table.  */
00948           set_cloexec_flag (channel, true);
00949           getloadavg_initialized = true;
00950         }
00951 #  else /* SUNOS_5 */
00952       /* We pass 0 for the kernel, corefile, and swapfile names
00953          to use the currently running kernel.  */
00954       kd = kvm_open (0, 0, 0, O_RDONLY, 0);
00955       if (kd != 0)
00956         {
00957           /* nlist the currently running kernel.  */
00958           kvm_nlist (kd, nl);
00959           offset = nl[0].n_value;
00960           getloadavg_initialized = true;
00961         }
00962 #  endif /* SUNOS_5 */
00963     }
00964 
00965   /* If we can, get the load average values.  */
00966   if (offset && getloadavg_initialized)
00967     {
00968       /* Try to read the load.  */
00969 #  ifndef SUNOS_5
00970       if (lseek (channel, offset, 0) == -1L
00971           || read (channel, (char *) load_ave, sizeof (load_ave))
00972           != sizeof (load_ave))
00973         {
00974           close (channel);
00975           getloadavg_initialized = false;
00976         }
00977 #  else  /* SUNOS_5 */
00978       if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
00979           != sizeof (load_ave))
00980         {
00981           kvm_close (kd);
00982           getloadavg_initialized = false;
00983         }
00984 #  endif /* SUNOS_5 */
00985     }
00986 
00987   if (offset == 0 || !getloadavg_initialized)
00988     return -1;
00989 # endif /* ! defined LDAV_DONE && defined LOAD_AVE_TYPE && ! defined __VMS */
00990 
00991 # if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) /* Including VMS.  */
00992   if (nelem > 0)
00993     loadavg[elem++] = LDAV_CVT (load_ave[0]);
00994   if (nelem > 1)
00995     loadavg[elem++] = LDAV_CVT (load_ave[1]);
00996   if (nelem > 2)
00997     loadavg[elem++] = LDAV_CVT (load_ave[2]);
00998 
00999 #  define LDAV_DONE
01000 # endif /* !LDAV_DONE && LOAD_AVE_TYPE */
01001 
01002 # if !defined LDAV_DONE
01003   /* Set errno to zero to indicate that there was no particular error;
01004      this function just can't work at all on this system.  */
01005   errno = 0;
01006   elem = -1;
01007 # endif
01008   return elem;
01009 }
01010 
01011 #endif /* ! HAVE_GETLOADAVG */
01012 
01013 #ifdef TEST
01014 int
01015 main (int argc, char **argv)
01016 {
01017   int naptime = 0;
01018 
01019   if (argc > 1)
01020     naptime = atoi (argv[1]);
01021 
01022   while (1)
01023     {
01024       double avg[3];
01025       int loads;
01026 
01027       errno = 0;                /* Don't be misled if it doesn't set errno.  */
01028       loads = getloadavg (avg, 3);
01029       if (loads == -1)
01030         {
01031           perror ("Error getting load average");
01032           return EXIT_FAILURE;
01033         }
01034       if (loads > 0)
01035         printf ("1-minute: %f  ", avg[0]);
01036       if (loads > 1)
01037         printf ("5-minute: %f  ", avg[1]);
01038       if (loads > 2)
01039         printf ("15-minute: %f  ", avg[2]);
01040       if (loads > 0)
01041         putchar ('\n');
01042 
01043       if (naptime == 0)
01044         break;
01045       sleep (naptime);
01046     }
01047 
01048   return EXIT_SUCCESS;
01049 }
01050 #endif /* TEST */