159336Sbostic /*
259336Sbostic  * loadst -- print current time and load statistics.
359336Sbostic  *				-- James Gosling @ CMU, May 1981
459336Sbostic  *  loadst [ -n ] [ interval ]
559336Sbostic  */
659336Sbostic 
759336Sbostic #define NO_SHORTNAMES  /* Do not want config to try to include remap.h */
859336Sbostic #include "../src/config.h"
959336Sbostic #include <stdio.h>
1059336Sbostic #include <pwd.h>
1159336Sbostic 
1259336Sbostic /* Define two macros KERNEL_FILE (file to find kernel symtab in)
1359336Sbostic    and LDAV_SYMBOL (symbol name to look for), based on system type.
1459336Sbostic    Also define NLIST_STRUCT if the type `nlist' is a structure we
1559336Sbostic    can get from nlist.h; otherwise must use a.out.h and initialize
1659336Sbostic    with strcpy.  Note that config.h may define NLIST_STRUCT
1759336Sbostic    for more modern USG systems.  */
1859336Sbostic 
1959336Sbostic 
2059336Sbostic #ifdef LOAD_AVE_TYPE
2159336Sbostic #ifndef NLIST_STRUCT
2259336Sbostic #include <a.out.h>
2359336Sbostic #else /* NLIST_STRUCT */
2459336Sbostic #include <nlist.h>
2559336Sbostic #endif /* NLIST_STRUCT */
2659336Sbostic #endif /* LOAD_AVE_TYPE */
2759336Sbostic 
2859336Sbostic /* All this serves to #include <param.h> and clean up the consequences.  */
2959336Sbostic #ifdef BSD
3059336Sbostic /* It appears param.h defines BSD and BSD4_3 in 4.3
3159336Sbostic    and is not considerate enough to avoid bombing out
3259336Sbostic    if they are already defined.  */
3359336Sbostic #undef BSD
3459336Sbostic #ifdef BSD4_3
3559336Sbostic #undef BSD4_3
3659336Sbostic #define XBSD4_3 /* XBSD4_3 says BSD4_3 is supposed to be defined.  */
3759336Sbostic #endif
3859336Sbostic #include <sys/param.h>
3959336Sbostic /* Now if BSD or BSD4_3 was defined and is no longer,
4059336Sbostic    define it again.  */
4159336Sbostic #ifndef BSD
4259336Sbostic #define BSD
4359336Sbostic #endif
4459336Sbostic #ifdef XBSD4_3
4559336Sbostic #ifndef BSD4_3
4659336Sbostic #define BSD4_3
4759336Sbostic #endif
4859336Sbostic #endif /* XBSD4_3 */
4959336Sbostic #endif /* BSD */
5059336Sbostic 
5159336Sbostic #ifdef USG
5259336Sbostic #include <time.h>
5359336Sbostic #include <sys/types.h>
5459336Sbostic #else /* not USG */
5559336Sbostic #include <sys/time.h>
5659336Sbostic #ifdef LOAD_AVE_TYPE
5759336Sbostic #ifndef RTU
5859336Sbostic #ifndef UMAX
5959336Sbostic #ifdef DKSTAT_HEADER_FILE
6059336Sbostic #include <sys/dkstat.h>
6159336Sbostic #else
6259336Sbostic #include <sys/dk.h>
6359336Sbostic #endif /* not DKSTAT_HEADER_FILE */
6459336Sbostic #endif /* UMAX */
6559336Sbostic #endif /* not RTU */
6659336Sbostic #endif /* LOAD_AVE_TYPE */
6759336Sbostic #endif /* USG */
6859336Sbostic 
6959336Sbostic #include <sys/stat.h>
7059336Sbostic 
7159336Sbostic #ifdef BSD
7259336Sbostic #include <sys/ioctl.h>
7359336Sbostic #endif /* BSD */
7459336Sbostic 
7559336Sbostic #ifdef UMAX
7659336Sbostic /*
7759336Sbostic  *  UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
7859336Sbostic  *  have a /dev/kmem.  Information about the workings of the running kernel
7959336Sbostic  *  can be gathered with inq_stats system calls.
8059336Sbostic  */
8159336Sbostic #include <sys/sysdefs.h>
8259336Sbostic #include <sys/syscall.h>
8359336Sbostic #include <sys/statistics.h>
8459336Sbostic #include <sys/procstats.h>
8559336Sbostic #include <sys/sysstats.h>
8659336Sbostic #endif /* UMAX */
8759336Sbostic 
8859336Sbostic /* We don't want Emacs's macro definitions for these USG primitives. */
8959336Sbostic 
9059336Sbostic #undef open
9159336Sbostic #undef read
9259336Sbostic #undef close
9359336Sbostic 
9459336Sbostic struct tm *localtime ();
9559336Sbostic 
9659336Sbostic #ifndef DKXFER_SYMBOL
9759336Sbostic #define DKXFER_SYMBOL "_dk_xfer"
9859336Sbostic #endif
9959336Sbostic #ifndef CPTIME_SYMBOL
10059336Sbostic #define CPTIME_SYMBOL "_cp_time"
10159336Sbostic #endif
10259336Sbostic 
10359336Sbostic #ifdef LOAD_AVE_TYPE
10459336Sbostic #ifndef NLIST_STRUCT
10559336Sbostic struct nlist nl[2];
10659336Sbostic #else /* NLIST_STRUCT */
10759336Sbostic struct nlist nl[] =
10859336Sbostic   {
10959336Sbostic     { LDAV_SYMBOL },
11059336Sbostic #if defined (CPUSTATES) && defined (DK_NDRIVE)
11159336Sbostic #define	X_CPTIME	1
11259336Sbostic     { CPTIME_SYMBOL },
11359336Sbostic #define	X_DKXFER	2
11459336Sbostic     { DKXFER_SYMBOL },
11559336Sbostic #endif /* have CPUSTATES and DK_NDRIVE */
11659336Sbostic     { 0 },
11759336Sbostic   };
11859336Sbostic #endif /* NLIST_STRUCT */
11959336Sbostic #endif /* LOAD_AVE_TYPE */
12059336Sbostic 
12159336Sbostic #if defined (CPUSTATES) && defined (DK_NDRIVE)
12259336Sbostic 
12359336Sbostic struct
12459336Sbostic {
12559336Sbostic   long	time[CPUSTATES];
12659336Sbostic   long	xfer[DK_NDRIVE];
12759336Sbostic } s, s1;
12859336Sbostic 
12959336Sbostic double	etime;
13059336Sbostic 
13159336Sbostic #endif /* have CPUSTATES and DK_NDRIVE */
13259336Sbostic 
13359336Sbostic int nflag;			/* -n flag -- no newline */
13459336Sbostic int uflag;			/* -u flag -- user current user ID rather
13559336Sbostic 				   than login user ID */
13659336Sbostic int repetition;			/* repetition interval */
13759336Sbostic 
13859336Sbostic #ifdef LOAD_AVE_TYPE
13959336Sbostic LOAD_AVE_TYPE load_average ();
14059336Sbostic #endif /* LOAD_AVE_TYPE */
14159336Sbostic 
main(argc,argv)14259336Sbostic main (argc, argv)
14359336Sbostic      char  **argv;
14459336Sbostic {
14559336Sbostic   register int kmem, i;
14659336Sbostic   char *mail;
14759336Sbostic   char *user_name;
14859336Sbostic   struct stat st;
14959336Sbostic #ifdef LOAD_AVE_TYPE
15059336Sbostic   LOAD_AVE_TYPE load;
15159336Sbostic #endif /* LOAD_AVE_TYPE */
15259336Sbostic 
15359336Sbostic   kmem = open ("/dev/kmem", 0);
15459336Sbostic 
15559336Sbostic #ifdef LOAD_AVE_TYPE
15659336Sbostic #ifndef NLIST_STRUCT
15759336Sbostic   strcpy (nl[0].n_name, LDAV_SYMBOL);
15859336Sbostic   strcpy (nl[1].n_name, "");
15959336Sbostic #endif /* not NLIST_STRUCT */
16059336Sbostic 
16159336Sbostic   nlist (KERNEL_FILE, nl);
16259336Sbostic #endif /* LOAD_AVE_TYPE */
16359336Sbostic 
16459336Sbostic   while (--argc > 0)
16559336Sbostic     {
16659336Sbostic       argv++;
16759336Sbostic       if (strcmp (*argv, "-n") == 0)
16859336Sbostic 	nflag++;
16959336Sbostic       else if (strcmp (*argv, "-u") == 0)
17059336Sbostic 	uflag++;
17159336Sbostic       else
17259336Sbostic 	if ((repetition = atoi (*argv)) <= 0)
17359336Sbostic 	  {
17459336Sbostic 	    fprintf (stderr, "Bogus argument: %s\n", *argv);
17559336Sbostic 	    exit (1);
17659336Sbostic 	  }
17759336Sbostic     }
17859336Sbostic 
17959336Sbostic   user_name = uflag ? ((struct passwd *) getpwuid (getuid ())) -> pw_name
18059336Sbostic #ifdef USG
18159336Sbostic     : (char *) getenv ("LOGNAME");
18259336Sbostic #else
18359336Sbostic     : (char *) getenv ("USER");
18459336Sbostic #endif
18559336Sbostic 
18659336Sbostic   mail = (char *) getenv ("MAIL");
18759336Sbostic 
18859336Sbostic   if (mail == 0)
18959336Sbostic     {
19059336Sbostic       mail = (char *) malloc (strlen (user_name) + 30);
19159336Sbostic 
192*59337Sbostic #ifdef BSD4_4
193*59337Sbostic       sprintf (mail, "/var/mail/%s", user_name);
194*59337Sbostic #elif defined (USG) && ! defined (XENIX)
19559336Sbostic       sprintf (mail, "/usr/mail/%s", user_name);
19659336Sbostic #else /* Xenix, or not USG */
19759336Sbostic       sprintf (mail, "/usr/spool/mail/%s", user_name);
19859336Sbostic #endif /* Xenix, or not USG */
19959336Sbostic     }
20059336Sbostic 
20159336Sbostic   if (stat (mail, &st) >= 0
20259336Sbostic       && (st.st_mode & S_IFMT) == S_IFDIR)
20359336Sbostic     {
20459336Sbostic       strcat (mail, "/");
20559336Sbostic       strcat (mail, user_name);
20659336Sbostic     }
20759336Sbostic 
20859336Sbostic   while (1)
20959336Sbostic     {
21059336Sbostic       register struct tm *nowt;
21159336Sbostic       long now;
21259336Sbostic 
21359336Sbostic       time (&now);
21459336Sbostic       nowt = localtime (&now);
21559336Sbostic 
21659336Sbostic       printf ("%d:%02d%s ",
21759336Sbostic 	      ((nowt->tm_hour + 11) % 12) + 1,
21859336Sbostic 	      nowt->tm_min,
21959336Sbostic 	      nowt->tm_hour >= 12 ? "pm" : "am");
22059336Sbostic 
22159336Sbostic #ifdef LOAD_AVE_TYPE
22259336Sbostic       load = load_average (kmem);
22359336Sbostic       if (load != (LOAD_AVE_TYPE) -1)
22459336Sbostic 	printf("%.2f", LOAD_AVE_CVT (load) / 100.0);
22559336Sbostic #endif /* LOAD_AVE_TYPE */
22659336Sbostic 
22759336Sbostic       printf ("%s",
22859336Sbostic 	      ((stat (mail, &st) >= 0 && st.st_size > 0)
22959336Sbostic 	       ? " Mail"
23059336Sbostic 	       : ""));
23159336Sbostic 
23259336Sbostic #if defined (CPUSTATES) && defined (DK_NDRIVE)
23359336Sbostic       if (kmem >= 0)
23459336Sbostic 	{
23559336Sbostic 	  lseek (kmem, (long) nl[X_CPTIME].n_value, 0);
23659336Sbostic 	  read (kmem, s.time, sizeof s.time);
23759336Sbostic 	  lseek (kmem, (long) nl[X_DKXFER].n_value, 0);
23859336Sbostic 	  read (kmem, s.xfer, sizeof s.xfer);
23959336Sbostic 	  etime = 0;
24059336Sbostic 	  for (i = 0; i < DK_NDRIVE; i++)
24159336Sbostic 	    {
24259336Sbostic 	      register t = s.xfer[i];
24359336Sbostic 	      s.xfer[i] -= s1.xfer[i];
24459336Sbostic 	      s1.xfer[i] = t;
24559336Sbostic 	    }
24659336Sbostic #ifndef BSD4_3
24759336Sbostic 	  for (i = 0; i < CPUSTATES; i++)
24859336Sbostic 	    {
24959336Sbostic 	      register t = s.time[i];
25059336Sbostic 	      s.time[i] -= s1.time[i];
25159336Sbostic 	      s1.time[i] = t;
25259336Sbostic 	      etime += s.time[i];
25359336Sbostic 	    }
25459336Sbostic 	  if (etime == 0.)
25559336Sbostic 	    etime = 1.;
25659336Sbostic 	  etime /= 60.;
25759336Sbostic 
25859336Sbostic #else
25959336Sbostic 	  {
26059336Sbostic 	    static struct timeval tv, tv1;
26159336Sbostic 	    gettimeofday (&tv, 0);
26259336Sbostic 	    etime = (tv.tv_sec - tv1.tv_sec)
26359336Sbostic 		+ (tv.tv_usec - tv1.tv_usec) / 1.0e6;
26459336Sbostic 	    tv1 = tv;
26559336Sbostic 	  }
26659336Sbostic #endif
26759336Sbostic 	  {   register max = s.xfer[0];
26859336Sbostic 	      for (i = 1; i < DK_NDRIVE; i++)
26959336Sbostic 		if (s.xfer[i] > max)
27059336Sbostic 		  max = s.xfer[i];
27159336Sbostic 	      printf ("[%d]", (int) (max / etime + 0.5));
27259336Sbostic 	    }
27359336Sbostic 	}
27459336Sbostic #endif /* have CPUSTATES and DK_NDRIVE */
27559336Sbostic       if (!nflag)
27659336Sbostic 	putchar ('\n');
27759336Sbostic       fflush (stdout);
27859336Sbostic       if (repetition <= 0)
27959336Sbostic 	break;
28059336Sbostic       sleep (repetition);
28159336Sbostic 
28259336Sbostic #ifdef BSD
28359336Sbostic       /* We are about to loop back and write another unit of output.  */
28459336Sbostic       /* If previous output has not yet been read by Emacs, flush it
28559336Sbostic 	 so the pty output buffer never gets full and Emacs
28659336Sbostic 	 can always get the latest update right away.  */
28759336Sbostic       /* ??? Someone should write a USG version of this code!  */
28859336Sbostic       {
28959336Sbostic 	int zero = 0;
29059336Sbostic 
29159336Sbostic 	ioctl (fileno (stdout), TIOCFLUSH, &zero);
29259336Sbostic       }
29359336Sbostic #endif
29459336Sbostic     }
29559336Sbostic }
29659336Sbostic 
29759336Sbostic #ifdef LOAD_AVE_TYPE
29859336Sbostic 
29959336Sbostic LOAD_AVE_TYPE
load_average(kmem)30059336Sbostic load_average (kmem)
30159336Sbostic      int kmem;
30259336Sbostic {
30359336Sbostic #ifdef UMAX
30459336Sbostic 
30559336Sbostic   int i, j;
30659336Sbostic   double sum;
30759336Sbostic   struct proc_summary proc_sum_data;
30859336Sbostic   struct stat_descr proc_info;
30959336Sbostic 
31059336Sbostic   proc_info.sd_next = NULL;
31159336Sbostic   proc_info.sd_subsys = SUBSYS_PROC;
31259336Sbostic   proc_info.sd_type = PROCTYPE_SUMMARY;
31359336Sbostic   proc_info.sd_addr = (char *) &proc_sum_data;
31459336Sbostic   proc_info.sd_size = sizeof (struct proc_summary);
31559336Sbostic   proc_info.sd_sizeused = 0;
31659336Sbostic 
31759336Sbostic   if (inq_stats (1, &proc_info) != 0 )
31859336Sbostic     {
31959336Sbostic       perror ("sysline proc summary inq_stats");
32059336Sbostic       exit (1);
32159336Sbostic     }
32259336Sbostic   /*
32359336Sbostic    * Generate current load average.
32459336Sbostic    */
32559336Sbostic   sum = 0;
32659336Sbostic   for (i = proc_sum_data.ps_nrunidx, j = 0; j < 12; j++)
32759336Sbostic     {
32859336Sbostic       sum += proc_sum_data.ps_nrun[i];
32959336Sbostic       if (--i < 0)
33059336Sbostic 	i = 179;
33159336Sbostic     }
33259336Sbostic   return sum / 12;
33359336Sbostic 
33459336Sbostic #else /* not UMAX */
33559336Sbostic 
33659336Sbostic   if (kmem >= 0)
33759336Sbostic     {
33859336Sbostic       LOAD_AVE_TYPE avenrun[3];
33959336Sbostic       avenrun[0] = 0;
34059336Sbostic #ifdef HAVE_GETLOADAVG
34159336Sbostic       (void) getloadavg(avenrun, 3);
34259336Sbostic #else
34359336Sbostic       lseek (kmem, (long) nl[0].n_value, 0);
34459336Sbostic       read (kmem, avenrun, sizeof (avenrun));
34559336Sbostic #endif
34659336Sbostic       return avenrun[0];
34759336Sbostic     }
34859336Sbostic   else
34959336Sbostic     return (LOAD_AVE_TYPE) -1;
35059336Sbostic 
35159336Sbostic #endif /* UMAX */
35259336Sbostic }
35359336Sbostic 
35459336Sbostic #endif /* LOAD_AVE_TYPE */
355