Merge changes to getloadavg.c from coreutils and Emacs; this
[gnulib.git] / lib / getloadavg.c
index b27c3d4..dce4117 100644 (file)
@@ -1,6 +1,10 @@
 /* Get the system load averages.
-   Copyright (C) 1985, 86, 87, 88, 89, 91, 92, 93, 1994, 1995, 1997
-       Free Software Foundation, Inc.
+
+   Copyright (C) 1985, 1986, 1987, 1988, 1989, 1991, 1992, 1993, 1994,
+   1995, 1997, 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
+
+   NOTE: The canonical source of this file is maintained with gnulib.
+   Bugs can be reported to bug-gnulib@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
    LOAD_AVE_TYPE               Type of the load average array in the kernel.
                                Must be defined unless one of
                                apollo, DGUX, NeXT, or UMAX is defined;
+                                or we have libkstat;
                                otherwise, no load average is available.
-   NLIST_NAME_UNION            struct nlist has an n_un member, not n_name.
+   HAVE_NLIST_H                 nlist.h is available.  NLIST_STRUCT defaults
+                                to this.
+   NLIST_STRUCT                        Include nlist.h, not a.out.h, and
+                               the nlist n_name element is a pointer,
+                               not an array.
+   HAVE_STRUCT_NLIST_N_UN_N_NAME `n_un.n_name' is member of `struct nlist'.
    LINUX_LDAV_FILE             [__linux__]: File containing load averages.
+   HAVE_LOCALE_H                locale.h is available.
+   HAVE_SETLOCALE               The `setlocale' function is available.
 
    Specific system predefines this file uses, aside from setting
    default values if not emacs:
@@ -59,7 +71,7 @@
    VMS
    WINDOWS32                   No-op for Windows95/NT.
    __linux__                   Linux: assumes /proc filesystem mounted.
-                               Support from Michael K. Johnson.
+                               Support from Michael K. Johnson.
    __NetBSD__                  NetBSD: assumes /kern filesystem mounted.
 
    In addition, to avoid nesting many #ifdefs, we internally set
@@ -78,7 +90,7 @@
 /* Both the Emacs and non-Emacs sections want this.  Some
    configuration files' definitions for the LOAD_AVE_CVT macro (like
    sparc.h's) use macros like FSCALE, defined here.  */
-#ifdef unix
+#if defined (unix) || defined (__unix)
 # include <sys/param.h>
 #endif
 
 extern int errno;
 #endif
 
-#if HAVE_LOCALE_H
+#ifdef HAVE_LOCALE_H
 # include <locale.h>
 #endif
-#if !HAVE_SETLOCALE
-# define setlocale(Category, Locale) /* empty */
+#ifndef HAVE_SETLOCALE
+# define setlocale(Category, Locale) ((char *) NULL)
 #endif
 
+#include "cloexec.h"
+#include "xalloc.h"
+
 #ifndef HAVE_GETLOADAVG
 
 /* The existing Emacs configuration files define a macro called
@@ -114,7 +129,7 @@ extern int errno;
    LOAD_AVE_CVT, but future machine config files should just define
    LDAV_CVT directly.  */
 
-# if !defined(LDAV_CVT) && defined(LOAD_AVE_CVT)
+# if !defined (LDAV_CVT) && defined (LOAD_AVE_CVT)
 #  define LDAV_CVT(n) (LOAD_AVE_CVT (n) / 100.0)
 # endif
 
@@ -134,6 +149,12 @@ extern int errno;
 #  undef FSCALE
 # endif
 
+/* Same issues as for NeXT apply to the HURD-based GNU system.  */
+# ifdef __GNU__
+#  undef BSD
+#  undef FSCALE
+# endif /* __GNU__ */
+
 /* Set values that are different from the defaults, which are
    set a little farther down with #ifndef.  */
 
@@ -152,11 +173,11 @@ extern int errno;
 #  define sun
 # endif
 
-# if defined(hp300) && !defined(hpux)
+# if defined (hp300) && !defined (hpux)
 #  define MORE_BSD
 # endif
 
-# if defined(ultrix) && defined(mips)
+# if defined (ultrix) && defined (mips)
 #  define decstation
 # endif
 
@@ -164,7 +185,7 @@ extern int errno;
 #  define SVR4
 # endif
 
-# if (defined(sun) && defined(SVR4)) || defined (SOLARIS2)
+# if (defined (sun) && defined (SVR4)) || defined (SOLARIS2)
 #  define SUNOS_5
 # endif
 
@@ -236,7 +257,7 @@ extern int errno;
 #   define LOAD_AVE_TYPE long
 #  endif
 
-#  if defined(alliant) && defined(i860) /* Alliant FX/2800 */
+#  if defined (alliant) && defined (i860) /* Alliant FX/2800 */
 #   define LOAD_AVE_TYPE long
 #  endif
 
@@ -260,7 +281,7 @@ extern int errno;
 #  define FSCALE 1024.0
 # endif
 
-# if defined(alliant) && defined(i860) /* Alliant FX/2800 */
+# if defined (alliant) && defined (i860) /* Alliant FX/2800 */
 /* <sys/param.h> defines an incorrect value for FSCALE on an
    Alliant FX/2800 Concentrix 2.2, according to ghazi@noc.rutgers.edu.  */
 #  undef FSCALE
@@ -276,7 +297,7 @@ extern int errno;
 #   define FSCALE 2048.0
 #  endif
 
-#  if defined(MIPS) || defined(SVR4) || defined(decstation)
+#  if defined (MIPS) || defined (SVR4) || defined (decstation)
 #   define FSCALE 256
 #  endif
 
@@ -305,7 +326,13 @@ extern int errno;
 #  define LDAV_CVT(n) (((double) (n)) / FSCALE)
 # endif
 
-# if defined(sgi) || (defined(mips) && !defined(BSD))
+# ifndef NLIST_STRUCT
+#  if HAVE_NLIST_H
+#   define NLIST_STRUCT
+#  endif
+# endif
+
+# if defined (sgi) || (defined (mips) && !defined (BSD))
 #  define FIXUP_KERNEL_SYMBOL_ADDR(nl) ((nl)[0].n_value &= ~(1 << 31))
 # endif
 
@@ -318,7 +345,7 @@ extern int errno;
 #  define KERNEL_FILE "/hp-ux"
 # endif
 
-# if !defined(KERNEL_FILE) && (defined(_SEQUENT_) || defined(MIPS) || defined(SVR4) || defined(ISC) || defined (sgi) || (defined (ardent) && defined (titan)))
+# if !defined (KERNEL_FILE) && (defined (_SEQUENT_) || defined (MIPS) || defined (SVR4) || defined (ISC) || defined (sgi) || (defined (ardent) && defined (titan)))
 #  define KERNEL_FILE "/unix"
 # endif
 
@@ -327,7 +354,7 @@ extern int errno;
 #  define LDAV_SYMBOL "_Loadavg"
 # endif
 
-# if !defined(LDAV_SYMBOL) && ((defined(hpux) && !defined(hp9000s300)) || defined(_SEQUENT_) || defined(SVR4) || defined(ISC) || defined(sgi) || (defined (ardent) && defined (titan)) || defined (_AIX))
+# if !defined (LDAV_SYMBOL) && ((defined (hpux) && !defined (hp9000s300)) || defined (_SEQUENT_) || defined (SVR4) || defined (ISC) || defined (sgi) || (defined (ardent) && defined (titan)) || defined (_AIX))
 #  define LDAV_SYMBOL "avenrun"
 # endif
 
@@ -339,7 +366,7 @@ extern int errno;
 
 /* LOAD_AVE_TYPE should only get defined if we're going to use the
    nlist method.  */
-# if !defined(LOAD_AVE_TYPE) && (defined(BSD) || defined(LDAV_CVT) || defined(KERNEL_FILE) || defined(LDAV_SYMBOL))
+# if !defined (LOAD_AVE_TYPE) && (defined (BSD) || defined (LDAV_CVT) || defined (KERNEL_FILE) || defined (LDAV_SYMBOL))
 #  define LOAD_AVE_TYPE double
 # endif
 
@@ -347,11 +374,11 @@ extern int errno;
 
 #  ifndef VMS
 #   ifndef __linux__
-#    ifndef HAVE_NLIST_H
+#    ifndef NLIST_STRUCT
 #     include <a.out.h>
-#    else /* HAVE_NLIST_H */
+#    else /* NLIST_STRUCT */
 #     include <nlist.h>
-#    endif /* HAVE_NLIST_H */
+#    endif /* NLIST_STRUCT */
 
 #    ifdef SUNOS_5
 #     include <fcntl.h>
@@ -388,7 +415,7 @@ extern int errno;
 
 # endif /* LOAD_AVE_TYPE */
 
-# if defined(__GNU__) && !defined (NeXT)
+# if defined (__GNU__) && !defined (NeXT)
 /* Note that NeXT Openstep defines __GNU__ even though it should not.  */
 /* GNU system acts much like NeXT, for load average purposes,
    but not exactly.  */
@@ -435,7 +462,7 @@ extern int errno;
 #  include <sys/dg_sys_info.h>
 # endif
 
-# if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION)
+# if defined (HAVE_FCNTL_H) || defined (_POSIX_VERSION)
 #  include <fcntl.h>
 # else
 #  include <sys/file.h>
@@ -457,7 +484,7 @@ static unsigned int samples;
 static struct dg_sys_info_load_info load_info; /* what-a-mouthful! */
 # endif /* DGUX */
 
-# ifdef LOAD_AVE_TYPE
+# if !defined (HAVE_LIBKSTAT) && defined (LOAD_AVE_TYPE)
 /* File descriptor open to /dev/kmem or VMS load ave driver.  */
 static int channel;
 /* Nonzero iff channel is valid.  */
@@ -465,7 +492,7 @@ static int getloadavg_initialized;
 /* Offset in kmem to seek to read load average, or 0 means invalid.  */
 static long offset;
 
-#  if !defined(VMS) && !defined(sgi) && !defined(__linux__)
+#  if !defined (VMS) && !defined (sgi) && !defined (__linux__)
 static struct nlist nl[2];
 #  endif /* Not VMS or sgi */
 
@@ -473,7 +500,7 @@ static struct nlist nl[2];
 static kvm_t *kd;
 #  endif /* SUNOS_5 */
 
-# endif /* LOAD_AVE_TYPE */
+# endif /* LOAD_AVE_TYPE && !HAVE_LIBKSTAT */
 \f
 /* Put the 1 minute, 5 minute and 15 minute load averages
    into the first NELEM elements of LOADAVG.
@@ -481,9 +508,7 @@ static kvm_t *kd;
    or -1 if an error occurred.  */
 
 int
-getloadavg (loadavg, nelem)
-     double loadavg[];
-     int nelem;
+getloadavg (double loadavg[], int nelem)
 {
   int elem = 0;                        /* Return value.  */
 
@@ -506,7 +531,7 @@ getloadavg (loadavg, nelem)
   if (kc == 0)
     return -1;
   ksp = kstat_lookup (kc, "unix", 0, "system_misc");
-  if (ksp == 0 )
+  if (ksp == 0)
     return -1;
   if (kstat_read (kc, ksp, 0) == -1)
     return -1;
@@ -521,20 +546,20 @@ getloadavg (loadavg, nelem)
     }
 
   if (nelem >= 1)
-    loadavg[elem++] = (double) kn->value.ul/FSCALE;
+    loadavg[elem++] = (double) kn->value.ul / FSCALE;
 
   if (nelem >= 2)
     {
       kn = kstat_data_lookup (ksp, "avenrun_5min");
       if (kn != 0)
        {
-         loadavg[elem++] = (double) kn->value.ul/FSCALE;
+         loadavg[elem++] = (double) kn->value.ul / FSCALE;
 
          if (nelem >= 3)
            {
              kn = kstat_data_lookup (ksp, "avenrun_15min");
              if (kn != 0)
-               loadavg[elem++] = (double) kn->value.ul/FSCALE;
+               loadavg[elem++] = (double) kn->value.ul / FSCALE;
            }
        }
     }
@@ -570,6 +595,7 @@ getloadavg (loadavg, nelem)
   char ldavgbuf[40];
   double load_ave[3];
   int fd, count;
+  char *old_locale;
 
   fd = open (LINUX_LDAV_FILE, O_RDONLY);
   if (fd == -1)
@@ -580,10 +606,12 @@ getloadavg (loadavg, nelem)
     return -1;
 
   /* The following sscanf must use the C locale.  */
+  old_locale = xstrdup (setlocale (LC_NUMERIC, NULL));
   setlocale (LC_NUMERIC, "C");
   count = sscanf (ldavgbuf, "%lf %lf %lf",
                  &load_ave[0], &load_ave[1], &load_ave[2]);
-  setlocale (LC_NUMERIC, "");
+  setlocale (LC_NUMERIC, old_locale);
+  free (old_locale);
   if (count < 1)
     return -1;
 
@@ -799,8 +827,8 @@ getloadavg (loadavg, nelem)
   for (elem = 0; elem < nelem; elem++)
     loadavg[elem]
       = (load_ave.tl_lscale == 0
-       ? load_ave.tl_avenrun.d[elem]
-       : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
+        ? load_ave.tl_avenrun.d[elem]
+        : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
 # endif /* OSF_ALPHA */
 
 # if !defined (LDAV_DONE) && defined (VMS)
@@ -843,7 +871,7 @@ getloadavg (loadavg, nelem)
     return -1;
 # endif /* VMS */
 
-# if !defined (LDAV_DONE) && defined(LOAD_AVE_TYPE) && !defined(VMS)
+# if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) && !defined (VMS)
 
   /* UNIX-specific code -- read the average from /dev/kmem.  */
 
@@ -855,18 +883,18 @@ getloadavg (loadavg, nelem)
   if (offset == 0)
     {
 #  ifndef sgi
-#   ifndef HAVE_NLIST_H
+#   ifndef NLIST_STRUCT
       strcpy (nl[0].n_name, LDAV_SYMBOL);
       strcpy (nl[1].n_name, "");
-#   else /* HAVE_NLIST_H */
-#    ifdef NLIST_NAME_UNION
+#   else /* NLIST_STRUCT */
+#    ifdef HAVE_STRUCT_NLIST_N_UN_N_NAME
       nl[0].n_un.n_name = LDAV_SYMBOL;
       nl[1].n_un.n_name = 0;
-#    else /* not NLIST_NAME_UNION */
+#    else /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */
       nl[0].n_name = LDAV_SYMBOL;
       nl[1].n_name = 0;
-#    endif /* not NLIST_NAME_UNION */
-#   endif /* HAVE_NLIST_H */
+#    endif /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */
+#   endif /* NLIST_STRUCT */
 
 #   ifndef SUNOS_5
       if (
@@ -902,12 +930,7 @@ getloadavg (loadavg, nelem)
        {
          /* Set the channel to close on exec, so it does not
             litter any child's descriptor table.  */
-#   ifdef FD_SETFD
-#    ifndef FD_CLOEXEC
-#     define FD_CLOEXEC 1
-#    endif
-         (void) fcntl (channel, F_SETFD, FD_CLOEXEC);
-#   endif
+         set_cloexec_flag (channel, true);
          getloadavg_initialized = 1;
        }
 #  else /* SUNOS_5 */
@@ -939,9 +962,9 @@ getloadavg (loadavg, nelem)
 #  else  /* SUNOS_5 */
       if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
          != sizeof (load_ave))
-        {
-          kvm_close (kd);
-          getloadavg_initialized = 0;
+       {
+         kvm_close (kd);
+         getloadavg_initialized = 0;
        }
 #  endif /* SUNOS_5 */
     }
@@ -975,9 +998,7 @@ getloadavg (loadavg, nelem)
 \f
 #ifdef TEST
 void
-main (argc, argv)
-     int argc;
-     char **argv;
+main (int argc, char **argv)
 {
   int naptime = 0;