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