1*59336Sbostic /*
2*59336Sbostic  * loadst -- print current time and load statistics.
3*59336Sbostic  *				-- James Gosling @ CMU, May 1981
4*59336Sbostic  *  loadst [ -n ] [ interval ]
5*59336Sbostic  */
6*59336Sbostic 
7*59336Sbostic #define NO_SHORTNAMES  /* Do not want config to try to include remap.h */
8*59336Sbostic #include "../src/config.h"
9*59336Sbostic #include <stdio.h>
10*59336Sbostic #include <pwd.h>
11*59336Sbostic 
12*59336Sbostic /* Define two macros KERNEL_FILE (file to find kernel symtab in)
13*59336Sbostic    and LDAV_SYMBOL (symbol name to look for), based on system type.
14*59336Sbostic    Also define NLIST_STRUCT if the type `nlist' is a structure we
15*59336Sbostic    can get from nlist.h; otherwise must use a.out.h and initialize
16*59336Sbostic    with strcpy.  Note that config.h may define NLIST_STRUCT
17*59336Sbostic    for more modern USG systems.  */
18*59336Sbostic 
19*59336Sbostic 
20*59336Sbostic #ifdef LOAD_AVE_TYPE
21*59336Sbostic #ifndef NLIST_STRUCT
22*59336Sbostic #include <a.out.h>
23*59336Sbostic #else /* NLIST_STRUCT */
24*59336Sbostic #include <nlist.h>
25*59336Sbostic #endif /* NLIST_STRUCT */
26*59336Sbostic #endif /* LOAD_AVE_TYPE */
27*59336Sbostic 
28*59336Sbostic /* All this serves to #include <param.h> and clean up the consequences.  */
29*59336Sbostic #ifdef BSD
30*59336Sbostic /* It appears param.h defines BSD and BSD4_3 in 4.3
31*59336Sbostic    and is not considerate enough to avoid bombing out
32*59336Sbostic    if they are already defined.  */
33*59336Sbostic #undef BSD
34*59336Sbostic #ifdef BSD4_3
35*59336Sbostic #undef BSD4_3
36*59336Sbostic #define XBSD4_3 /* XBSD4_3 says BSD4_3 is supposed to be defined.  */
37*59336Sbostic #endif
38*59336Sbostic #include <sys/param.h>
39*59336Sbostic /* Now if BSD or BSD4_3 was defined and is no longer,
40*59336Sbostic    define it again.  */
41*59336Sbostic #ifndef BSD
42*59336Sbostic #define BSD
43*59336Sbostic #endif
44*59336Sbostic #ifdef XBSD4_3
45*59336Sbostic #ifndef BSD4_3
46*59336Sbostic #define BSD4_3
47*59336Sbostic #endif
48*59336Sbostic #endif /* XBSD4_3 */
49*59336Sbostic #endif /* BSD */
50*59336Sbostic 
51*59336Sbostic #ifdef USG
52*59336Sbostic #include <time.h>
53*59336Sbostic #include <sys/types.h>
54*59336Sbostic #else /* not USG */
55*59336Sbostic #include <sys/time.h>
56*59336Sbostic #ifdef LOAD_AVE_TYPE
57*59336Sbostic #ifndef RTU
58*59336Sbostic #ifndef UMAX
59*59336Sbostic #ifdef DKSTAT_HEADER_FILE
60*59336Sbostic #include <sys/dkstat.h>
61*59336Sbostic #else
62*59336Sbostic #include <sys/dk.h>
63*59336Sbostic #endif /* not DKSTAT_HEADER_FILE */
64*59336Sbostic #endif /* UMAX */
65*59336Sbostic #endif /* not RTU */
66*59336Sbostic #endif /* LOAD_AVE_TYPE */
67*59336Sbostic #endif /* USG */
68*59336Sbostic 
69*59336Sbostic #include <sys/stat.h>
70*59336Sbostic 
71*59336Sbostic #ifdef BSD
72*59336Sbostic #include <sys/ioctl.h>
73*59336Sbostic #endif /* BSD */
74*59336Sbostic 
75*59336Sbostic #ifdef UMAX
76*59336Sbostic /*
77*59336Sbostic  *  UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
78*59336Sbostic  *  have a /dev/kmem.  Information about the workings of the running kernel
79*59336Sbostic  *  can be gathered with inq_stats system calls.
80*59336Sbostic  */
81*59336Sbostic #include <sys/sysdefs.h>
82*59336Sbostic #include <sys/syscall.h>
83*59336Sbostic #include <sys/statistics.h>
84*59336Sbostic #include <sys/procstats.h>
85*59336Sbostic #include <sys/sysstats.h>
86*59336Sbostic #endif /* UMAX */
87*59336Sbostic 
88*59336Sbostic /* We don't want Emacs's macro definitions for these USG primitives. */
89*59336Sbostic 
90*59336Sbostic #undef open
91*59336Sbostic #undef read
92*59336Sbostic #undef close
93*59336Sbostic 
94*59336Sbostic struct tm *localtime ();
95*59336Sbostic 
96*59336Sbostic #ifndef DKXFER_SYMBOL
97*59336Sbostic #define DKXFER_SYMBOL "_dk_xfer"
98*59336Sbostic #endif
99*59336Sbostic #ifndef CPTIME_SYMBOL
100*59336Sbostic #define CPTIME_SYMBOL "_cp_time"
101*59336Sbostic #endif
102*59336Sbostic 
103*59336Sbostic #ifdef LOAD_AVE_TYPE
104*59336Sbostic #ifndef NLIST_STRUCT
105*59336Sbostic struct nlist nl[2];
106*59336Sbostic #else /* NLIST_STRUCT */
107*59336Sbostic struct nlist nl[] =
108*59336Sbostic   {
109*59336Sbostic     { LDAV_SYMBOL },
110*59336Sbostic #if defined (CPUSTATES) && defined (DK_NDRIVE)
111*59336Sbostic #define	X_CPTIME	1
112*59336Sbostic     { CPTIME_SYMBOL },
113*59336Sbostic #define	X_DKXFER	2
114*59336Sbostic     { DKXFER_SYMBOL },
115*59336Sbostic #endif /* have CPUSTATES and DK_NDRIVE */
116*59336Sbostic     { 0 },
117*59336Sbostic   };
118*59336Sbostic #endif /* NLIST_STRUCT */
119*59336Sbostic #endif /* LOAD_AVE_TYPE */
120*59336Sbostic 
121*59336Sbostic #if defined (CPUSTATES) && defined (DK_NDRIVE)
122*59336Sbostic 
123*59336Sbostic struct
124*59336Sbostic {
125*59336Sbostic   long	time[CPUSTATES];
126*59336Sbostic   long	xfer[DK_NDRIVE];
127*59336Sbostic } s, s1;
128*59336Sbostic 
129*59336Sbostic double	etime;
130*59336Sbostic 
131*59336Sbostic #endif /* have CPUSTATES and DK_NDRIVE */
132*59336Sbostic 
133*59336Sbostic int nflag;			/* -n flag -- no newline */
134*59336Sbostic int uflag;			/* -u flag -- user current user ID rather
135*59336Sbostic 				   than login user ID */
136*59336Sbostic int repetition;			/* repetition interval */
137*59336Sbostic 
138*59336Sbostic #ifdef LOAD_AVE_TYPE
139*59336Sbostic LOAD_AVE_TYPE load_average ();
140*59336Sbostic #endif /* LOAD_AVE_TYPE */
141*59336Sbostic 
142*59336Sbostic main (argc, argv)
143*59336Sbostic      char  **argv;
144*59336Sbostic {
145*59336Sbostic   register int kmem, i;
146*59336Sbostic   char *mail;
147*59336Sbostic   char *user_name;
148*59336Sbostic   struct stat st;
149*59336Sbostic #ifdef LOAD_AVE_TYPE
150*59336Sbostic   LOAD_AVE_TYPE load;
151*59336Sbostic #endif /* LOAD_AVE_TYPE */
152*59336Sbostic 
153*59336Sbostic   kmem = open ("/dev/kmem", 0);
154*59336Sbostic 
155*59336Sbostic #ifdef LOAD_AVE_TYPE
156*59336Sbostic #ifndef NLIST_STRUCT
157*59336Sbostic   strcpy (nl[0].n_name, LDAV_SYMBOL);
158*59336Sbostic   strcpy (nl[1].n_name, "");
159*59336Sbostic #endif /* not NLIST_STRUCT */
160*59336Sbostic 
161*59336Sbostic   nlist (KERNEL_FILE, nl);
162*59336Sbostic #endif /* LOAD_AVE_TYPE */
163*59336Sbostic 
164*59336Sbostic   while (--argc > 0)
165*59336Sbostic     {
166*59336Sbostic       argv++;
167*59336Sbostic       if (strcmp (*argv, "-n") == 0)
168*59336Sbostic 	nflag++;
169*59336Sbostic       else if (strcmp (*argv, "-u") == 0)
170*59336Sbostic 	uflag++;
171*59336Sbostic       else
172*59336Sbostic 	if ((repetition = atoi (*argv)) <= 0)
173*59336Sbostic 	  {
174*59336Sbostic 	    fprintf (stderr, "Bogus argument: %s\n", *argv);
175*59336Sbostic 	    exit (1);
176*59336Sbostic 	  }
177*59336Sbostic     }
178*59336Sbostic 
179*59336Sbostic   user_name = uflag ? ((struct passwd *) getpwuid (getuid ())) -> pw_name
180*59336Sbostic #ifdef USG
181*59336Sbostic     : (char *) getenv ("LOGNAME");
182*59336Sbostic #else
183*59336Sbostic     : (char *) getenv ("USER");
184*59336Sbostic #endif
185*59336Sbostic 
186*59336Sbostic   mail = (char *) getenv ("MAIL");
187*59336Sbostic 
188*59336Sbostic   if (mail == 0)
189*59336Sbostic     {
190*59336Sbostic       mail = (char *) malloc (strlen (user_name) + 30);
191*59336Sbostic 
192*59336Sbostic #if defined (USG) && ! defined (XENIX)
193*59336Sbostic       sprintf (mail, "/usr/mail/%s", user_name);
194*59336Sbostic #else /* Xenix, or not USG */
195*59336Sbostic       sprintf (mail, "/usr/spool/mail/%s", user_name);
196*59336Sbostic #endif /* Xenix, or not USG */
197*59336Sbostic     }
198*59336Sbostic 
199*59336Sbostic   if (stat (mail, &st) >= 0
200*59336Sbostic       && (st.st_mode & S_IFMT) == S_IFDIR)
201*59336Sbostic     {
202*59336Sbostic       strcat (mail, "/");
203*59336Sbostic       strcat (mail, user_name);
204*59336Sbostic     }
205*59336Sbostic 
206*59336Sbostic   while (1)
207*59336Sbostic     {
208*59336Sbostic       register struct tm *nowt;
209*59336Sbostic       long now;
210*59336Sbostic 
211*59336Sbostic       time (&now);
212*59336Sbostic       nowt = localtime (&now);
213*59336Sbostic 
214*59336Sbostic       printf ("%d:%02d%s ",
215*59336Sbostic 	      ((nowt->tm_hour + 11) % 12) + 1,
216*59336Sbostic 	      nowt->tm_min,
217*59336Sbostic 	      nowt->tm_hour >= 12 ? "pm" : "am");
218*59336Sbostic 
219*59336Sbostic #ifdef LOAD_AVE_TYPE
220*59336Sbostic       load = load_average (kmem);
221*59336Sbostic       if (load != (LOAD_AVE_TYPE) -1)
222*59336Sbostic 	printf("%.2f", LOAD_AVE_CVT (load) / 100.0);
223*59336Sbostic #endif /* LOAD_AVE_TYPE */
224*59336Sbostic 
225*59336Sbostic       printf ("%s",
226*59336Sbostic 	      ((stat (mail, &st) >= 0 && st.st_size > 0)
227*59336Sbostic 	       ? " Mail"
228*59336Sbostic 	       : ""));
229*59336Sbostic 
230*59336Sbostic #if defined (CPUSTATES) && defined (DK_NDRIVE)
231*59336Sbostic       if (kmem >= 0)
232*59336Sbostic 	{
233*59336Sbostic 	  lseek (kmem, (long) nl[X_CPTIME].n_value, 0);
234*59336Sbostic 	  read (kmem, s.time, sizeof s.time);
235*59336Sbostic 	  lseek (kmem, (long) nl[X_DKXFER].n_value, 0);
236*59336Sbostic 	  read (kmem, s.xfer, sizeof s.xfer);
237*59336Sbostic 	  etime = 0;
238*59336Sbostic 	  for (i = 0; i < DK_NDRIVE; i++)
239*59336Sbostic 	    {
240*59336Sbostic 	      register t = s.xfer[i];
241*59336Sbostic 	      s.xfer[i] -= s1.xfer[i];
242*59336Sbostic 	      s1.xfer[i] = t;
243*59336Sbostic 	    }
244*59336Sbostic #ifndef BSD4_3
245*59336Sbostic 	  for (i = 0; i < CPUSTATES; i++)
246*59336Sbostic 	    {
247*59336Sbostic 	      register t = s.time[i];
248*59336Sbostic 	      s.time[i] -= s1.time[i];
249*59336Sbostic 	      s1.time[i] = t;
250*59336Sbostic 	      etime += s.time[i];
251*59336Sbostic 	    }
252*59336Sbostic 	  if (etime == 0.)
253*59336Sbostic 	    etime = 1.;
254*59336Sbostic 	  etime /= 60.;
255*59336Sbostic 
256*59336Sbostic #else
257*59336Sbostic 	  {
258*59336Sbostic 	    static struct timeval tv, tv1;
259*59336Sbostic 	    gettimeofday (&tv, 0);
260*59336Sbostic 	    etime = (tv.tv_sec - tv1.tv_sec)
261*59336Sbostic 		+ (tv.tv_usec - tv1.tv_usec) / 1.0e6;
262*59336Sbostic 	    tv1 = tv;
263*59336Sbostic 	  }
264*59336Sbostic #endif
265*59336Sbostic 	  {   register max = s.xfer[0];
266*59336Sbostic 	      for (i = 1; i < DK_NDRIVE; i++)
267*59336Sbostic 		if (s.xfer[i] > max)
268*59336Sbostic 		  max = s.xfer[i];
269*59336Sbostic 	      printf ("[%d]", (int) (max / etime + 0.5));
270*59336Sbostic 	    }
271*59336Sbostic 	}
272*59336Sbostic #endif /* have CPUSTATES and DK_NDRIVE */
273*59336Sbostic       if (!nflag)
274*59336Sbostic 	putchar ('\n');
275*59336Sbostic       fflush (stdout);
276*59336Sbostic       if (repetition <= 0)
277*59336Sbostic 	break;
278*59336Sbostic       sleep (repetition);
279*59336Sbostic 
280*59336Sbostic #ifdef BSD
281*59336Sbostic       /* We are about to loop back and write another unit of output.  */
282*59336Sbostic       /* If previous output has not yet been read by Emacs, flush it
283*59336Sbostic 	 so the pty output buffer never gets full and Emacs
284*59336Sbostic 	 can always get the latest update right away.  */
285*59336Sbostic       /* ??? Someone should write a USG version of this code!  */
286*59336Sbostic       {
287*59336Sbostic 	int zero = 0;
288*59336Sbostic 
289*59336Sbostic 	ioctl (fileno (stdout), TIOCFLUSH, &zero);
290*59336Sbostic       }
291*59336Sbostic #endif
292*59336Sbostic     }
293*59336Sbostic }
294*59336Sbostic 
295*59336Sbostic #ifdef LOAD_AVE_TYPE
296*59336Sbostic 
297*59336Sbostic LOAD_AVE_TYPE
298*59336Sbostic load_average (kmem)
299*59336Sbostic      int kmem;
300*59336Sbostic {
301*59336Sbostic #ifdef UMAX
302*59336Sbostic 
303*59336Sbostic   int i, j;
304*59336Sbostic   double sum;
305*59336Sbostic   struct proc_summary proc_sum_data;
306*59336Sbostic   struct stat_descr proc_info;
307*59336Sbostic 
308*59336Sbostic   proc_info.sd_next = NULL;
309*59336Sbostic   proc_info.sd_subsys = SUBSYS_PROC;
310*59336Sbostic   proc_info.sd_type = PROCTYPE_SUMMARY;
311*59336Sbostic   proc_info.sd_addr = (char *) &proc_sum_data;
312*59336Sbostic   proc_info.sd_size = sizeof (struct proc_summary);
313*59336Sbostic   proc_info.sd_sizeused = 0;
314*59336Sbostic 
315*59336Sbostic   if (inq_stats (1, &proc_info) != 0 )
316*59336Sbostic     {
317*59336Sbostic       perror ("sysline proc summary inq_stats");
318*59336Sbostic       exit (1);
319*59336Sbostic     }
320*59336Sbostic   /*
321*59336Sbostic    * Generate current load average.
322*59336Sbostic    */
323*59336Sbostic   sum = 0;
324*59336Sbostic   for (i = proc_sum_data.ps_nrunidx, j = 0; j < 12; j++)
325*59336Sbostic     {
326*59336Sbostic       sum += proc_sum_data.ps_nrun[i];
327*59336Sbostic       if (--i < 0)
328*59336Sbostic 	i = 179;
329*59336Sbostic     }
330*59336Sbostic   return sum / 12;
331*59336Sbostic 
332*59336Sbostic #else /* not UMAX */
333*59336Sbostic 
334*59336Sbostic   if (kmem >= 0)
335*59336Sbostic     {
336*59336Sbostic       LOAD_AVE_TYPE avenrun[3];
337*59336Sbostic       avenrun[0] = 0;
338*59336Sbostic #ifdef HAVE_GETLOADAVG
339*59336Sbostic       (void) getloadavg(avenrun, 3);
340*59336Sbostic #else
341*59336Sbostic       lseek (kmem, (long) nl[0].n_value, 0);
342*59336Sbostic       read (kmem, avenrun, sizeof (avenrun));
343*59336Sbostic #endif
344*59336Sbostic       return avenrun[0];
345*59336Sbostic     }
346*59336Sbostic   else
347*59336Sbostic     return (LOAD_AVE_TYPE) -1;
348*59336Sbostic 
349*59336Sbostic #endif /* UMAX */
350*59336Sbostic }
351*59336Sbostic 
352*59336Sbostic #endif /* LOAD_AVE_TYPE */
353