1/* Copyright (c) 1993-2002
2 *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
20 *
21 ****************************************************************
22 */
23
24#include <sys/types.h>
25#include <fcntl.h>
26#ifdef ultrix
27# include <sys/fixpoint.h>
28#endif
29
30/* mach stuff included here to prevent index macro conflict */
31#ifdef NeXT
32# include <sys/version.h>
33# if KERNEL_MAJOR_VERSION > 2
34#  include <mach/mach.h>
35# else
36#  include <mach.h>
37# endif
38#endif
39
40#include "config.h"
41#include "screen.h"
42
43#include "extern.h"
44
45#ifdef LOADAV
46
47static int GetLoadav __P((void));
48
49static LOADAV_TYPE loadav[LOADAV_NUM];
50static int loadok;
51
52
53
54/***************************************************************/
55
56#if defined(linux) && !defined(LOADAV_DONE)
57#define LOADAV_DONE
58/*
59 * This is the easy way. It relies in /proc being mounted.
60 * For the big and ugly way refer to previous screen version.
61 */
62void
63InitLoadav()
64{
65  loadok = 1;
66}
67
68static int
69GetLoadav()
70{
71  FILE *fp;
72  char buf[128], *s;
73  int i;
74  double d, e;
75
76  if ((fp = secfopen("/proc/loadavg", "r")) == NULL)
77    return 0;
78  *buf = 0;
79  fgets(buf, sizeof(buf), fp);
80  fclose(fp);
81  /* can't use fscanf because the decimal point symbol depends on
82   * the locale but the kernel uses always '.'.
83   */
84  s = buf;
85  for (i = 0; i < (LOADAV_NUM > 3 ? 3 : LOADAV_NUM); i++)
86    {
87      d = e = 0;
88      while(*s == ' ')
89	s++;
90      if (*s == 0)
91	break;
92      for(;;)
93	{
94	  if (*s == '.')
95	    e = 1;
96	  else if (*s >= '0' && *s <= '9')
97	    {
98	      d = d * 10 + (*s - '0');
99	      if (e)
100		e *= 10;
101	    }
102	  else
103	    break;
104	  s++;
105	}
106      loadav[i] = e ? d / e : d;
107    }
108  return i;
109}
110#endif /* linux */
111
112/***************************************************************/
113
114#if defined(LOADAV_GETLOADAVG) && !defined(LOADAV_DONE)
115#define LOADAV_DONE
116void
117InitLoadav()
118{
119  loadok = 1;
120}
121
122static int
123GetLoadav()
124{
125  return getloadavg(loadav, LOADAV_NUM);
126}
127#endif
128
129/***************************************************************/
130
131#if defined(apollo) && !defined(LOADAV_DONE)
132#define LOADAV_DONE
133void
134InitLoadav()
135{
136  loadok = 1;
137}
138
139static int
140GetLoadav()
141{
142  proc1_$get_loadav(loadav);
143  return LOADAV_NUM;
144}
145#endif
146
147/***************************************************************/
148
149#if defined(NeXT) && !defined(LOADAV_DONE)
150#define LOADAV_DONE
151
152static processor_set_t default_set;
153
154void
155InitLoadav()
156{
157  kern_return_t error;
158
159  error = processor_set_default(host_self(), &default_set);
160  if (error != KERN_SUCCESS)
161    mach_error("Error calling processor_set_default", error);
162  else
163    loadok = 1;
164}
165
166static int
167GetLoadav()
168{
169  unsigned int info_count;
170  struct processor_set_basic_info info;
171  host_t host;
172
173  info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
174  if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO, &host, (processor_set_info_t)&info, &info_count) != KERN_SUCCESS)
175    return 0;
176  loadav[0] = (float)info.load_average / LOAD_SCALE;
177  return 1;
178}
179#endif
180
181/***************************************************************/
182
183#if defined(sun) && defined(SVR4) && !defined(LOADAV_DONE)
184#define LOADAV_DONE
185
186#include <kstat.h>
187
188static kstat_ctl_t *kc;
189
190void
191InitLoadav()
192{
193  loadok = (kc = kstat_open()) != 0;
194}
195
196static int
197GetLoadav()
198{
199  kstat_t *ks;
200  kstat_named_t *avgs[3];
201  int i;
202
203  kstat_chain_update(kc);
204  if ((ks = kstat_lookup(kc, "unix", -1, "system_misc")) == 0 || kstat_read(kc, ks, (void *)0) == -1)
205    return (loadok = 0);
206  avgs[0] = kstat_data_lookup(ks, "avenrun_1min");
207  avgs[1] = kstat_data_lookup(ks, "avenrun_5min");
208  avgs[2] = kstat_data_lookup(ks, "avenrun_15min");
209  for (i = 0; i < 3; i++)
210    {
211      if (avgs[i] == 0 || avgs[i]->data_type != KSTAT_DATA_ULONG)
212        return (loadok = 0);
213      loadav[i] = avgs[i]->value.ul;
214    }
215  return 3;
216}
217
218#endif
219
220/***************************************************************/
221
222#if defined(__osf__) && defined(__alpha) && !defined(LOADAV_DONE)
223#define LOADAV_DONE
224
225struct rtentry; struct mbuf;	/* shut up gcc on OSF/1 4.0 */
226#include <sys/table.h>
227
228void
229InitLoadav()
230{
231  loadok = 1;
232}
233
234static int
235GetLoadav()
236{
237  struct tbl_loadavg tbl;
238  int i;
239
240  if (table(TBL_LOADAVG, 0, &tbl, 1, sizeof(struct tbl_loadavg)) != 1)
241    return 0;
242
243  if (tbl.tl_lscale)
244    {
245      /* in long */
246      for (i = 0; i < LOADAV_NUM; i++)
247        loadav[i] = (double) tbl.tl_avenrun.l[i] / tbl.tl_lscale;
248    }
249  else
250    {
251      /* in double */
252      for (i = 0; i < LOADAV_NUM; i++)
253        loadav[i] = tbl.tl_avenrun.d[i];
254    }
255  return LOADAV_NUM;
256}
257#endif
258
259/***************************************************************/
260
261#if !defined(LOADAV_DONE)
262/*
263 * The old fashion way: open kernel and read avenrun
264 *
265 * Header File includes
266 */
267
268# ifdef NLIST_STRUCT
269#  include <nlist.h>
270# else
271#  include <a.out.h>
272# endif
273# ifndef NLIST_DECLARED
274extern int nlist __P((char *, struct nlist *));
275# endif
276
277#ifdef LOADAV_USE_NLIST64
278# define nlist nlist64
279#endif
280
281static struct nlist nl[2];
282static int kmemf;
283
284#ifdef _IBMR2
285# define nlist(u,l) knlist(l,1,sizeof(*l))
286#endif
287
288void
289InitLoadav()
290{
291  debug("Init Kmem...\n");
292  if ((kmemf = open("/dev/kmem", O_RDONLY)) == -1)
293    return;
294# if !defined(_AUX_SOURCE) && !defined(AUX)
295#  ifdef NLIST_NAME_UNION
296  nl[0].n_un.n_name = LOADAV_AVENRUN;
297#  else
298  nl[0].n_name = LOADAV_AVENRUN;
299#  endif
300# else
301  strncpy(nl[0].n_name, LOADAV_AVENRUN, sizeof(nl[0].n_name));
302# endif
303  debug2("Searching in %s for %s\n", LOADAV_UNIX, nl[0].n_name);
304  nlist(LOADAV_UNIX, nl);
305  if (nl[0].n_value == 0)
306    {
307      close(kmemf);
308      return;
309    }
310# if 0		/* no longer needed (Al.Smith@aeschi.ch.eu.org) */
311#  ifdef sgi
312  nl[0].n_value &= (unsigned long)-1 >> 1;	/* clear upper bit */
313#  endif /* sgi */
314# endif
315  debug1("AvenrunSym found (0x%lx)!!\n", nl[0].n_value);
316  loadok = 1;
317}
318
319static int
320GetLoadav()
321{
322  if (lseek(kmemf, (off_t) nl[0].n_value, 0) == (off_t)-1)
323    return 0;
324  if (read(kmemf, (char *) loadav, sizeof(loadav)) != sizeof(loadav))
325    return 0;
326  return LOADAV_NUM;
327}
328#endif
329
330/***************************************************************/
331
332#ifndef FIX_TO_DBL
333#define FIX_TO_DBL(l) ((double)(l) /  LOADAV_SCALE)
334#endif
335
336void
337AddLoadav(p)
338char *p;
339{
340  int i, j;
341  if (loadok == 0)
342    return;
343  j = GetLoadav();
344  for (i = 0; i < j; i++)
345    {
346      sprintf(p, " %2.2f" + !i, FIX_TO_DBL(loadav[i]));
347      p += strlen(p);
348    }
349}
350
351#endif /* LOADAV */
352