(getloadavg): Don't assume setlocale returns nonnull.
[gnulib.git] / lib / getloadavg.c
1 /* Get the system load averages.
2
3    Copyright (C) 1985, 1986, 1987, 1988, 1989, 1991, 1992, 1993, 1994,
4    1995, 1997, 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
5
6    NOTE: The canonical source of this file is maintained with gnulib.
7    Bugs can be reported to bug-gnulib@gnu.org.
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2, or (at your option)
12    any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
22    USA.  */
23
24 /* Compile-time symbols that this file uses:
25
26    HAVE_PSTAT_GETDYNAMIC        Define this if your system has the
27                                 pstat_getdynamic function.  I think it
28                                 is unique to HPUX9.  The best way to get the
29                                 definition is through the AC_FUNC_GETLOADAVG
30                                 macro that comes with autoconf 2.13 or newer.
31                                 If that isn't an option, then just put
32                                 AC_CHECK_FUNCS(pstat_getdynamic) in your
33                                 configure.in file.
34    FIXUP_KERNEL_SYMBOL_ADDR()   Adjust address in returned struct nlist.
35    KERNEL_FILE                  Pathname of the kernel to nlist.
36    LDAV_CVT()                   Scale the load average from the kernel.
37                                 Returns a double.
38    LDAV_SYMBOL                  Name of kernel symbol giving load average.
39    LOAD_AVE_TYPE                Type of the load average array in the kernel.
40                                 Must be defined unless one of
41                                 apollo, DGUX, NeXT, or UMAX is defined;
42                                 or we have libkstat;
43                                 otherwise, no load average is available.
44    HAVE_NLIST_H                 nlist.h is available.  NLIST_STRUCT defaults
45                                 to this.
46    NLIST_STRUCT                 Include nlist.h, not a.out.h, and
47                                 the nlist n_name element is a pointer,
48                                 not an array.
49    HAVE_STRUCT_NLIST_N_UN_N_NAME `n_un.n_name' is member of `struct nlist'.
50    LINUX_LDAV_FILE              [__linux__]: File containing load averages.
51    HAVE_LOCALE_H                locale.h is available.
52    HAVE_SETLOCALE               The `setlocale' function is available.
53
54    Specific system predefines this file uses, aside from setting
55    default values if not emacs:
56
57    apollo
58    BSD                          Real BSD, not just BSD-like.
59    convex
60    DGUX
61    eunice                       UNIX emulator under VMS.
62    hpux
63    __MSDOS__                    No-op for MSDOS.
64    NeXT
65    sgi
66    sequent                      Sequent Dynix 3.x.x (BSD)
67    _SEQUENT_                    Sequent DYNIX/ptx 1.x.x (SYSV)
68    sony_news                    NEWS-OS (works at least for 4.1C)
69    UMAX
70    UMAX4_3
71    VMS
72    WINDOWS32                    No-op for Windows95/NT.
73    __linux__                    Linux: assumes /proc filesystem mounted.
74                                 Support from Michael K. Johnson.
75    __NetBSD__                   NetBSD: assumes /kern filesystem mounted.
76
77    In addition, to avoid nesting many #ifdefs, we internally set
78    LDAV_DONE to indicate that the load average has been computed.
79
80    We also #define LDAV_PRIVILEGED if a program will require
81    special installation to be able to call getloadavg.  */
82
83 /* This should always be first.  */
84 #ifdef HAVE_CONFIG_H
85 # include <config.h>
86 #endif
87
88 #include <sys/types.h>
89
90 /* Both the Emacs and non-Emacs sections want this.  Some
91    configuration files' definitions for the LOAD_AVE_CVT macro (like
92    sparc.h's) use macros like FSCALE, defined here.  */
93 #if defined (unix) || defined (__unix)
94 # include <sys/param.h>
95 #endif
96
97
98 /* Exclude all the code except the test program at the end
99    if the system has its own `getloadavg' function.
100
101    The declaration of `errno' is needed by the test program
102    as well as the function itself, so it comes first.  */
103
104 #include <errno.h>
105
106 #ifndef errno
107 extern int errno;
108 #endif
109
110 #ifdef HAVE_LOCALE_H
111 # include <locale.h>
112 #endif
113 #ifndef HAVE_SETLOCALE
114 # define setlocale(Category, Locale) ((char *) NULL)
115 #endif
116
117 #include "cloexec.h"
118 #include "xalloc.h"
119
120 #ifndef HAVE_GETLOADAVG
121
122 /* The existing Emacs configuration files define a macro called
123    LOAD_AVE_CVT, which accepts a value of type LOAD_AVE_TYPE, and
124    returns the load average multiplied by 100.  What we actually want
125    is a macro called LDAV_CVT, which returns the load average as an
126    unmultiplied double.
127
128    For backwards compatibility, we'll define LDAV_CVT in terms of
129    LOAD_AVE_CVT, but future machine config files should just define
130    LDAV_CVT directly.  */
131
132 # if !defined (LDAV_CVT) && defined (LOAD_AVE_CVT)
133 #  define LDAV_CVT(n) (LOAD_AVE_CVT (n) / 100.0)
134 # endif
135
136 # if !defined (BSD) && defined (ultrix)
137 /* Ultrix behaves like BSD on Vaxen.  */
138 #  define BSD
139 # endif
140
141 # ifdef NeXT
142 /* NeXT in the 2.{0,1,2} releases defines BSD in <sys/param.h>, which
143    conflicts with the definition understood in this file, that this
144    really is BSD. */
145 #  undef BSD
146
147 /* NeXT defines FSCALE in <sys/param.h>.  However, we take FSCALE being
148    defined to mean that the nlist method should be used, which is not true.  */
149 #  undef FSCALE
150 # endif
151
152 /* Same issues as for NeXT apply to the HURD-based GNU system.  */
153 # ifdef __GNU__
154 #  undef BSD
155 #  undef FSCALE
156 # endif /* __GNU__ */
157
158 /* Set values that are different from the defaults, which are
159    set a little farther down with #ifndef.  */
160
161
162 /* Some shorthands.  */
163
164 # if defined (HPUX) && !defined (hpux)
165 #  define hpux
166 # endif
167
168 # if defined (__hpux) && !defined (hpux)
169 #  define hpux
170 # endif
171
172 # if defined (__sun) && !defined (sun)
173 #  define sun
174 # endif
175
176 # if defined (hp300) && !defined (hpux)
177 #  define MORE_BSD
178 # endif
179
180 # if defined (ultrix) && defined (mips)
181 #  define decstation
182 # endif
183
184 # if defined (__SVR4) && !defined (SVR4)
185 #  define SVR4
186 # endif
187
188 # if (defined (sun) && defined (SVR4)) || defined (SOLARIS2)
189 #  define SUNOS_5
190 # endif
191
192 # if defined (__osf__) && (defined (__alpha) || defined (__alpha__))
193 #  define OSF_ALPHA
194 #  include <sys/mbuf.h>
195 #  include <sys/socket.h>
196 #  include <net/route.h>
197 #  include <sys/table.h>
198 # endif
199
200 # if defined (__osf__) && (defined (mips) || defined (__mips__))
201 #  define OSF_MIPS
202 #  include <sys/table.h>
203 # endif
204
205 /* UTek's /bin/cc on the 4300 has no architecture specific cpp define by
206    default, but _MACH_IND_SYS_TYPES is defined in <sys/types.h>.  Combine
207    that with a couple of other things and we'll have a unique match.  */
208 # if !defined (tek4300) && defined (unix) && defined (m68k) && defined (mc68000) && defined (mc68020) && defined (_MACH_IND_SYS_TYPES)
209 #  define tek4300                       /* Define by emacs, but not by other users.  */
210 # endif
211
212
213 /* VAX C can't handle multi-line #ifs, or lines longer than 256 chars.  */
214 # ifndef LOAD_AVE_TYPE
215
216 #  ifdef MORE_BSD
217 #   define LOAD_AVE_TYPE long
218 #  endif
219
220 #  ifdef sun
221 #   define LOAD_AVE_TYPE long
222 #  endif
223
224 #  ifdef decstation
225 #   define LOAD_AVE_TYPE long
226 #  endif
227
228 #  ifdef _SEQUENT_
229 #   define LOAD_AVE_TYPE long
230 #  endif
231
232 #  ifdef sgi
233 #   define LOAD_AVE_TYPE long
234 #  endif
235
236 #  ifdef SVR4
237 #   define LOAD_AVE_TYPE long
238 #  endif
239
240 #  ifdef sony_news
241 #   define LOAD_AVE_TYPE long
242 #  endif
243
244 #  ifdef sequent
245 #   define LOAD_AVE_TYPE long
246 #  endif
247
248 #  ifdef OSF_ALPHA
249 #   define LOAD_AVE_TYPE long
250 #  endif
251
252 #  if defined (ardent) && defined (titan)
253 #   define LOAD_AVE_TYPE long
254 #  endif
255
256 #  ifdef tek4300
257 #   define LOAD_AVE_TYPE long
258 #  endif
259
260 #  if defined (alliant) && defined (i860) /* Alliant FX/2800 */
261 #   define LOAD_AVE_TYPE long
262 #  endif
263
264 #  ifdef _AIX
265 #   define LOAD_AVE_TYPE long
266 #  endif
267
268 #  ifdef convex
269 #   define LOAD_AVE_TYPE double
270 #   ifndef LDAV_CVT
271 #    define LDAV_CVT(n) (n)
272 #   endif
273 #  endif
274
275 # endif /* No LOAD_AVE_TYPE.  */
276
277 # ifdef OSF_ALPHA
278 /* <sys/param.h> defines an incorrect value for FSCALE on Alpha OSF/1,
279    according to ghazi@noc.rutgers.edu.  */
280 #  undef FSCALE
281 #  define FSCALE 1024.0
282 # endif
283
284 # if defined (alliant) && defined (i860) /* Alliant FX/2800 */
285 /* <sys/param.h> defines an incorrect value for FSCALE on an
286    Alliant FX/2800 Concentrix 2.2, according to ghazi@noc.rutgers.edu.  */
287 #  undef FSCALE
288 #  define FSCALE 100.0
289 # endif
290
291
292 # ifndef        FSCALE
293
294 /* SunOS and some others define FSCALE in sys/param.h.  */
295
296 #  ifdef MORE_BSD
297 #   define FSCALE 2048.0
298 #  endif
299
300 #  if defined (MIPS) || defined (SVR4) || defined (decstation)
301 #   define FSCALE 256
302 #  endif
303
304 #  if defined (sgi) || defined (sequent)
305 /* Sometimes both MIPS and sgi are defined, so FSCALE was just defined
306    above under #ifdef MIPS.  But we want the sgi value.  */
307 #   undef FSCALE
308 #   define FSCALE 1000.0
309 #  endif
310
311 #  if defined (ardent) && defined (titan)
312 #   define FSCALE 65536.0
313 #  endif
314
315 #  ifdef tek4300
316 #   define FSCALE 100.0
317 #  endif
318
319 #  ifdef _AIX
320 #   define FSCALE 65536.0
321 #  endif
322
323 # endif /* Not FSCALE.  */
324
325 # if !defined (LDAV_CVT) && defined (FSCALE)
326 #  define LDAV_CVT(n) (((double) (n)) / FSCALE)
327 # endif
328
329 # ifndef NLIST_STRUCT
330 #  if HAVE_NLIST_H
331 #   define NLIST_STRUCT
332 #  endif
333 # endif
334
335 # if defined (sgi) || (defined (mips) && !defined (BSD))
336 #  define FIXUP_KERNEL_SYMBOL_ADDR(nl) ((nl)[0].n_value &= ~(1 << 31))
337 # endif
338
339
340 # if !defined (KERNEL_FILE) && defined (sequent)
341 #  define KERNEL_FILE "/dynix"
342 # endif
343
344 # if !defined (KERNEL_FILE) && defined (hpux)
345 #  define KERNEL_FILE "/hp-ux"
346 # endif
347
348 # if !defined (KERNEL_FILE) && (defined (_SEQUENT_) || defined (MIPS) || defined (SVR4) || defined (ISC) || defined (sgi) || (defined (ardent) && defined (titan)))
349 #  define KERNEL_FILE "/unix"
350 # endif
351
352
353 # if !defined (LDAV_SYMBOL) && defined (alliant)
354 #  define LDAV_SYMBOL "_Loadavg"
355 # endif
356
357 # if !defined (LDAV_SYMBOL) && ((defined (hpux) && !defined (hp9000s300)) || defined (_SEQUENT_) || defined (SVR4) || defined (ISC) || defined (sgi) || (defined (ardent) && defined (titan)) || defined (_AIX))
358 #  define LDAV_SYMBOL "avenrun"
359 # endif
360
361 # ifdef HAVE_UNISTD_H
362 #  include <unistd.h>
363 # endif
364
365 # include <stdio.h>
366
367 /* LOAD_AVE_TYPE should only get defined if we're going to use the
368    nlist method.  */
369 # if !defined (LOAD_AVE_TYPE) && (defined (BSD) || defined (LDAV_CVT) || defined (KERNEL_FILE) || defined (LDAV_SYMBOL))
370 #  define LOAD_AVE_TYPE double
371 # endif
372
373 # ifdef LOAD_AVE_TYPE
374
375 #  ifndef VMS
376 #   ifndef __linux__
377 #    ifndef NLIST_STRUCT
378 #     include <a.out.h>
379 #    else /* NLIST_STRUCT */
380 #     include <nlist.h>
381 #    endif /* NLIST_STRUCT */
382
383 #    ifdef SUNOS_5
384 #     include <fcntl.h>
385 #     include <kvm.h>
386 #     include <kstat.h>
387 #    endif
388
389 #    if defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC)
390 #     include <sys/pstat.h>
391 #    endif
392
393 #    ifndef KERNEL_FILE
394 #     define KERNEL_FILE "/vmunix"
395 #    endif /* KERNEL_FILE */
396
397 #    ifndef LDAV_SYMBOL
398 #     define LDAV_SYMBOL "_avenrun"
399 #    endif /* LDAV_SYMBOL */
400 #   endif /* __linux__ */
401
402 #  else /* VMS */
403
404 #   ifndef eunice
405 #    include <iodef.h>
406 #    include <descrip.h>
407 #   else /* eunice */
408 #    include <vms/iodef.h>
409 #   endif /* eunice */
410 #  endif /* VMS */
411
412 #  ifndef LDAV_CVT
413 #   define LDAV_CVT(n) ((double) (n))
414 #  endif /* !LDAV_CVT */
415
416 # endif /* LOAD_AVE_TYPE */
417
418 # if defined (__GNU__) && !defined (NeXT)
419 /* Note that NeXT Openstep defines __GNU__ even though it should not.  */
420 /* GNU system acts much like NeXT, for load average purposes,
421    but not exactly.  */
422 #  define NeXT
423 #  define host_self mach_host_self
424 # endif
425
426 # ifdef NeXT
427 #  ifdef HAVE_MACH_MACH_H
428 #   include <mach/mach.h>
429 #  else
430 #   include <mach.h>
431 #  endif
432 # endif /* NeXT */
433
434 # ifdef sgi
435 #  include <sys/sysmp.h>
436 # endif /* sgi */
437
438 # ifdef UMAX
439 #  include <stdio.h>
440 #  include <signal.h>
441 #  include <sys/time.h>
442 #  include <sys/wait.h>
443 #  include <sys/syscall.h>
444
445 #  ifdef UMAX_43
446 #   include <machine/cpu.h>
447 #   include <inq_stats/statistics.h>
448 #   include <inq_stats/sysstats.h>
449 #   include <inq_stats/cpustats.h>
450 #   include <inq_stats/procstats.h>
451 #  else /* Not UMAX_43.  */
452 #   include <sys/sysdefs.h>
453 #   include <sys/statistics.h>
454 #   include <sys/sysstats.h>
455 #   include <sys/cpudefs.h>
456 #   include <sys/cpustats.h>
457 #   include <sys/procstats.h>
458 #  endif /* Not UMAX_43.  */
459 # endif /* UMAX */
460
461 # ifdef DGUX
462 #  include <sys/dg_sys_info.h>
463 # endif
464
465 # if defined (HAVE_FCNTL_H) || defined (_POSIX_VERSION)
466 #  include <fcntl.h>
467 # else
468 #  include <sys/file.h>
469 # endif
470 \f
471 /* Avoid static vars inside a function since in HPUX they dump as pure.  */
472
473 # ifdef NeXT
474 static processor_set_t default_set;
475 static int getloadavg_initialized;
476 # endif /* NeXT */
477
478 # ifdef UMAX
479 static unsigned int cpus = 0;
480 static unsigned int samples;
481 # endif /* UMAX */
482
483 # ifdef DGUX
484 static struct dg_sys_info_load_info load_info;  /* what-a-mouthful! */
485 # endif /* DGUX */
486
487 # if !defined (HAVE_LIBKSTAT) && defined (LOAD_AVE_TYPE)
488 /* File descriptor open to /dev/kmem or VMS load ave driver.  */
489 static int channel;
490 /* Nonzero iff channel is valid.  */
491 static int getloadavg_initialized;
492 /* Offset in kmem to seek to read load average, or 0 means invalid.  */
493 static long offset;
494
495 #  if !defined (VMS) && !defined (sgi) && !defined (__linux__)
496 static struct nlist nl[2];
497 #  endif /* Not VMS or sgi */
498
499 #  ifdef SUNOS_5
500 static kvm_t *kd;
501 #  endif /* SUNOS_5 */
502
503 # endif /* LOAD_AVE_TYPE && !HAVE_LIBKSTAT */
504 \f
505 /* Put the 1 minute, 5 minute and 15 minute load averages
506    into the first NELEM elements of LOADAVG.
507    Return the number written (never more than 3, but may be less than NELEM),
508    or -1 if an error occurred.  */
509
510 int
511 getloadavg (double loadavg[], int nelem)
512 {
513   int elem = 0;                 /* Return value.  */
514
515 # ifdef NO_GET_LOAD_AVG
516 #  define LDAV_DONE
517   /* Set errno to zero to indicate that there was no particular error;
518      this function just can't work at all on this system.  */
519   errno = 0;
520   elem = -1;
521 # endif
522
523 # if !defined (LDAV_DONE) && defined (HAVE_LIBKSTAT)
524 /* Use libkstat because we don't have to be root.  */
525 #  define LDAV_DONE
526   kstat_ctl_t *kc;
527   kstat_t *ksp;
528   kstat_named_t *kn;
529
530   kc = kstat_open ();
531   if (kc == 0)
532     return -1;
533   ksp = kstat_lookup (kc, "unix", 0, "system_misc");
534   if (ksp == 0)
535     return -1;
536   if (kstat_read (kc, ksp, 0) == -1)
537     return -1;
538
539
540   kn = kstat_data_lookup (ksp, "avenrun_1min");
541   if (kn == 0)
542     {
543       /* Return -1 if no load average information is available.  */
544       nelem = 0;
545       elem = -1;
546     }
547
548   if (nelem >= 1)
549     loadavg[elem++] = (double) kn->value.ul / FSCALE;
550
551   if (nelem >= 2)
552     {
553       kn = kstat_data_lookup (ksp, "avenrun_5min");
554       if (kn != 0)
555         {
556           loadavg[elem++] = (double) kn->value.ul / FSCALE;
557
558           if (nelem >= 3)
559             {
560               kn = kstat_data_lookup (ksp, "avenrun_15min");
561               if (kn != 0)
562                 loadavg[elem++] = (double) kn->value.ul / FSCALE;
563             }
564         }
565     }
566
567   kstat_close (kc);
568 # endif /* HAVE_LIBKSTAT */
569
570 # if !defined (LDAV_DONE) && defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC)
571 /* Use pstat_getdynamic() because we don't have to be root.  */
572 #  define LDAV_DONE
573 #  undef LOAD_AVE_TYPE
574
575   struct pst_dynamic dyn_info;
576   if (pstat_getdynamic (&dyn_info, sizeof (dyn_info), 0, 0) < 0)
577     return -1;
578   if (nelem > 0)
579     loadavg[elem++] = dyn_info.psd_avg_1_min;
580   if (nelem > 1)
581     loadavg[elem++] = dyn_info.psd_avg_5_min;
582   if (nelem > 2)
583     loadavg[elem++] = dyn_info.psd_avg_15_min;
584
585 # endif /* hpux && HAVE_PSTAT_GETDYNAMIC */
586
587 # if !defined (LDAV_DONE) && defined (__linux__)
588 #  define LDAV_DONE
589 #  undef LOAD_AVE_TYPE
590
591 #  ifndef LINUX_LDAV_FILE
592 #   define LINUX_LDAV_FILE "/proc/loadavg"
593 #  endif
594
595   char ldavgbuf[40];
596   double load_ave[3];
597   int fd, count;
598   char *old_locale;
599
600   fd = open (LINUX_LDAV_FILE, O_RDONLY);
601   if (fd == -1)
602     return -1;
603   count = read (fd, ldavgbuf, 40);
604   (void) close (fd);
605   if (count <= 0)
606     return -1;
607
608   /* The following sscanf must use the C locale.  */
609   old_locale = setlocale (LC_NUMERIC, NULL);
610   if (old_locale)
611     old_locale = xstrdup (old_locale);
612   setlocale (LC_NUMERIC, "C");
613   count = sscanf (ldavgbuf, "%lf %lf %lf",
614                   &load_ave[0], &load_ave[1], &load_ave[2]);
615   setlocale (LC_NUMERIC, old_locale);
616   free (old_locale);
617   if (count < 1)
618     return -1;
619
620   for (elem = 0; elem < nelem && elem < count; elem++)
621     loadavg[elem] = load_ave[elem];
622
623   return elem;
624
625 # endif /* __linux__ */
626
627 # if !defined (LDAV_DONE) && defined (__NetBSD__)
628 #  define LDAV_DONE
629 #  undef LOAD_AVE_TYPE
630
631 #  ifndef NETBSD_LDAV_FILE
632 #   define NETBSD_LDAV_FILE "/kern/loadavg"
633 #  endif
634
635   unsigned long int load_ave[3], scale;
636   int count;
637   FILE *fp;
638
639   fp = fopen (NETBSD_LDAV_FILE, "r");
640   if (fp == NULL)
641     return -1;
642   count = fscanf (fp, "%lu %lu %lu %lu\n",
643                   &load_ave[0], &load_ave[1], &load_ave[2],
644                   &scale);
645   (void) fclose (fp);
646   if (count != 4)
647     return -1;
648
649   for (elem = 0; elem < nelem; elem++)
650     loadavg[elem] = (double) load_ave[elem] / (double) scale;
651
652   return elem;
653
654 # endif /* __NetBSD__ */
655
656 # if !defined (LDAV_DONE) && defined (NeXT)
657 #  define LDAV_DONE
658   /* The NeXT code was adapted from iscreen 3.2.  */
659
660   host_t host;
661   struct processor_set_basic_info info;
662   unsigned info_count;
663
664   /* We only know how to get the 1-minute average for this system,
665      so even if the caller asks for more than 1, we only return 1.  */
666
667   if (!getloadavg_initialized)
668     {
669       if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS)
670         getloadavg_initialized = 1;
671     }
672
673   if (getloadavg_initialized)
674     {
675       info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
676       if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
677                               (processor_set_info_t) &info, &info_count)
678           != KERN_SUCCESS)
679         getloadavg_initialized = 0;
680       else
681         {
682           if (nelem > 0)
683             loadavg[elem++] = (double) info.load_average / LOAD_SCALE;
684         }
685     }
686
687   if (!getloadavg_initialized)
688     return -1;
689 # endif /* NeXT */
690
691 # if !defined (LDAV_DONE) && defined (UMAX)
692 #  define LDAV_DONE
693 /* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
694    have a /dev/kmem.  Information about the workings of the running kernel
695    can be gathered with inq_stats system calls.
696    We only know how to get the 1-minute average for this system.  */
697
698   struct proc_summary proc_sum_data;
699   struct stat_descr proc_info;
700   double load;
701   register unsigned int i, j;
702
703   if (cpus == 0)
704     {
705       register unsigned int c, i;
706       struct cpu_config conf;
707       struct stat_descr desc;
708
709       desc.sd_next = 0;
710       desc.sd_subsys = SUBSYS_CPU;
711       desc.sd_type = CPUTYPE_CONFIG;
712       desc.sd_addr = (char *) &conf;
713       desc.sd_size = sizeof conf;
714
715       if (inq_stats (1, &desc))
716         return -1;
717
718       c = 0;
719       for (i = 0; i < conf.config_maxclass; ++i)
720         {
721           struct class_stats stats;
722           bzero ((char *) &stats, sizeof stats);
723
724           desc.sd_type = CPUTYPE_CLASS;
725           desc.sd_objid = i;
726           desc.sd_addr = (char *) &stats;
727           desc.sd_size = sizeof stats;
728
729           if (inq_stats (1, &desc))
730             return -1;
731
732           c += stats.class_numcpus;
733         }
734       cpus = c;
735       samples = cpus < 2 ? 3 : (2 * cpus / 3);
736     }
737
738   proc_info.sd_next = 0;
739   proc_info.sd_subsys = SUBSYS_PROC;
740   proc_info.sd_type = PROCTYPE_SUMMARY;
741   proc_info.sd_addr = (char *) &proc_sum_data;
742   proc_info.sd_size = sizeof (struct proc_summary);
743   proc_info.sd_sizeused = 0;
744
745   if (inq_stats (1, &proc_info) != 0)
746     return -1;
747
748   load = proc_sum_data.ps_nrunnable;
749   j = 0;
750   for (i = samples - 1; i > 0; --i)
751     {
752       load += proc_sum_data.ps_nrun[j];
753       if (j++ == PS_NRUNSIZE)
754         j = 0;
755     }
756
757   if (nelem > 0)
758     loadavg[elem++] = load / samples / cpus;
759 # endif /* UMAX */
760
761 # if !defined (LDAV_DONE) && defined (DGUX)
762 #  define LDAV_DONE
763   /* This call can return -1 for an error, but with good args
764      it's not supposed to fail.  The first argument is for no
765      apparent reason of type `long int *'.  */
766   dg_sys_info ((long int *) &load_info,
767                DG_SYS_INFO_LOAD_INFO_TYPE,
768                DG_SYS_INFO_LOAD_VERSION_0);
769
770   if (nelem > 0)
771     loadavg[elem++] = load_info.one_minute;
772   if (nelem > 1)
773     loadavg[elem++] = load_info.five_minute;
774   if (nelem > 2)
775     loadavg[elem++] = load_info.fifteen_minute;
776 # endif /* DGUX */
777
778 # if !defined (LDAV_DONE) && defined (apollo)
779 #  define LDAV_DONE
780 /* Apollo code from lisch@mentorg.com (Ray Lischner).
781
782    This system call is not documented.  The load average is obtained as
783    three long integers, for the load average over the past minute,
784    five minutes, and fifteen minutes.  Each value is a scaled integer,
785    with 16 bits of integer part and 16 bits of fraction part.
786
787    I'm not sure which operating system first supported this system call,
788    but I know that SR10.2 supports it.  */
789
790   extern void proc1_$get_loadav ();
791   unsigned long load_ave[3];
792
793   proc1_$get_loadav (load_ave);
794
795   if (nelem > 0)
796     loadavg[elem++] = load_ave[0] / 65536.0;
797   if (nelem > 1)
798     loadavg[elem++] = load_ave[1] / 65536.0;
799   if (nelem > 2)
800     loadavg[elem++] = load_ave[2] / 65536.0;
801 # endif /* apollo */
802
803 # if !defined (LDAV_DONE) && defined (OSF_MIPS)
804 #  define LDAV_DONE
805
806   struct tbl_loadavg load_ave;
807   table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
808   loadavg[elem++]
809     = (load_ave.tl_lscale == 0
810        ? load_ave.tl_avenrun.d[0]
811        : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale));
812 # endif /* OSF_MIPS */
813
814 # if !defined (LDAV_DONE) && (defined (__MSDOS__) || defined (WINDOWS32))
815 #  define LDAV_DONE
816
817   /* A faithful emulation is going to have to be saved for a rainy day.  */
818   for ( ; elem < nelem; elem++)
819     {
820       loadavg[elem] = 0.0;
821     }
822 # endif  /* __MSDOS__ || WINDOWS32 */
823
824 # if !defined (LDAV_DONE) && defined (OSF_ALPHA)
825 #  define LDAV_DONE
826
827   struct tbl_loadavg load_ave;
828   table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
829   for (elem = 0; elem < nelem; elem++)
830     loadavg[elem]
831       = (load_ave.tl_lscale == 0
832          ? load_ave.tl_avenrun.d[elem]
833          : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
834 # endif /* OSF_ALPHA */
835
836 # if !defined (LDAV_DONE) && defined (VMS)
837   /* VMS specific code -- read from the Load Ave driver.  */
838
839   LOAD_AVE_TYPE load_ave[3];
840   static int getloadavg_initialized = 0;
841 #  ifdef eunice
842   struct
843   {
844     int dsc$w_length;
845     char *dsc$a_pointer;
846   } descriptor;
847 #  endif
848
849   /* Ensure that there is a channel open to the load ave device.  */
850   if (!getloadavg_initialized)
851     {
852       /* Attempt to open the channel.  */
853 #  ifdef eunice
854       descriptor.dsc$w_length = 18;
855       descriptor.dsc$a_pointer = "$$VMS_LOAD_AVERAGE";
856 #  else
857       $DESCRIPTOR (descriptor, "LAV0:");
858 #  endif
859       if (sys$assign (&descriptor, &channel, 0, 0) & 1)
860         getloadavg_initialized = 1;
861     }
862
863   /* Read the load average vector.  */
864   if (getloadavg_initialized
865       && !(sys$qiow (0, channel, IO$_READVBLK, 0, 0, 0,
866                      load_ave, 12, 0, 0, 0, 0) & 1))
867     {
868       sys$dassgn (channel);
869       getloadavg_initialized = 0;
870     }
871
872   if (!getloadavg_initialized)
873     return -1;
874 # endif /* VMS */
875
876 # if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) && !defined (VMS)
877
878   /* UNIX-specific code -- read the average from /dev/kmem.  */
879
880 #  define LDAV_PRIVILEGED               /* This code requires special installation.  */
881
882   LOAD_AVE_TYPE load_ave[3];
883
884   /* Get the address of LDAV_SYMBOL.  */
885   if (offset == 0)
886     {
887 #  ifndef sgi
888 #   ifndef NLIST_STRUCT
889       strcpy (nl[0].n_name, LDAV_SYMBOL);
890       strcpy (nl[1].n_name, "");
891 #   else /* NLIST_STRUCT */
892 #    ifdef HAVE_STRUCT_NLIST_N_UN_N_NAME
893       nl[0].n_un.n_name = LDAV_SYMBOL;
894       nl[1].n_un.n_name = 0;
895 #    else /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */
896       nl[0].n_name = LDAV_SYMBOL;
897       nl[1].n_name = 0;
898 #    endif /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */
899 #   endif /* NLIST_STRUCT */
900
901 #   ifndef SUNOS_5
902       if (
903 #    if !(defined (_AIX) && !defined (ps2))
904           nlist (KERNEL_FILE, nl)
905 #    else  /* _AIX */
906           knlist (nl, 1, sizeof (nl[0]))
907 #    endif
908           >= 0)
909           /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i.  */
910           {
911 #    ifdef FIXUP_KERNEL_SYMBOL_ADDR
912             FIXUP_KERNEL_SYMBOL_ADDR (nl);
913 #    endif
914             offset = nl[0].n_value;
915           }
916 #   endif /* !SUNOS_5 */
917 #  else  /* sgi */
918       int ldav_off;
919
920       ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
921       if (ldav_off != -1)
922         offset = (long) ldav_off & 0x7fffffff;
923 #  endif /* sgi */
924     }
925
926   /* Make sure we have /dev/kmem open.  */
927   if (!getloadavg_initialized)
928     {
929 #  ifndef SUNOS_5
930       channel = open ("/dev/kmem", 0);
931       if (channel >= 0)
932         {
933           /* Set the channel to close on exec, so it does not
934              litter any child's descriptor table.  */
935           set_cloexec_flag (channel, true);
936           getloadavg_initialized = 1;
937         }
938 #  else /* SUNOS_5 */
939       /* We pass 0 for the kernel, corefile, and swapfile names
940          to use the currently running kernel.  */
941       kd = kvm_open (0, 0, 0, O_RDONLY, 0);
942       if (kd != 0)
943         {
944           /* nlist the currently running kernel.  */
945           kvm_nlist (kd, nl);
946           offset = nl[0].n_value;
947           getloadavg_initialized = 1;
948         }
949 #  endif /* SUNOS_5 */
950     }
951
952   /* If we can, get the load average values.  */
953   if (offset && getloadavg_initialized)
954     {
955       /* Try to read the load.  */
956 #  ifndef SUNOS_5
957       if (lseek (channel, offset, 0) == -1L
958           || read (channel, (char *) load_ave, sizeof (load_ave))
959           != sizeof (load_ave))
960         {
961           close (channel);
962           getloadavg_initialized = 0;
963         }
964 #  else  /* SUNOS_5 */
965       if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
966           != sizeof (load_ave))
967         {
968           kvm_close (kd);
969           getloadavg_initialized = 0;
970         }
971 #  endif /* SUNOS_5 */
972     }
973
974   if (offset == 0 || !getloadavg_initialized)
975     return -1;
976 # endif /* LOAD_AVE_TYPE and not VMS */
977
978 # if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) /* Including VMS.  */
979   if (nelem > 0)
980     loadavg[elem++] = LDAV_CVT (load_ave[0]);
981   if (nelem > 1)
982     loadavg[elem++] = LDAV_CVT (load_ave[1]);
983   if (nelem > 2)
984     loadavg[elem++] = LDAV_CVT (load_ave[2]);
985
986 #  define LDAV_DONE
987 # endif /* !LDAV_DONE && LOAD_AVE_TYPE */
988
989 # ifdef LDAV_DONE
990   return elem;
991 # else
992   /* Set errno to zero to indicate that there was no particular error;
993      this function just can't work at all on this system.  */
994   errno = 0;
995   return -1;
996 # endif
997 }
998
999 #endif /* ! HAVE_GETLOADAVG */
1000 \f
1001 #ifdef TEST
1002 void
1003 main (int argc, char **argv)
1004 {
1005   int naptime = 0;
1006
1007   if (argc > 1)
1008     naptime = atoi (argv[1]);
1009
1010   while (1)
1011     {
1012       double avg[3];
1013       int loads;
1014
1015       errno = 0;                /* Don't be misled if it doesn't set errno.  */
1016       loads = getloadavg (avg, 3);
1017       if (loads == -1)
1018         {
1019           perror ("Error getting load average");
1020           exit (1);
1021         }
1022       if (loads > 0)
1023         printf ("1-minute: %f  ", avg[0]);
1024       if (loads > 1)
1025         printf ("5-minute: %f  ", avg[1]);
1026       if (loads > 2)
1027         printf ("15-minute: %f  ", avg[2]);
1028       if (loads > 0)
1029         putchar ('\n');
1030
1031       if (naptime == 0)
1032         break;
1033       sleep (naptime);
1034     }
1035
1036   exit (0);
1037 }
1038 #endif /* TEST */