60 #include <utmpx.h>
61 #include <sys/utsname.h>
62 #include <sys/stat.h>
63 #include <sys/mkdev.h>
64 #include <dirent.h>
65 #include <procfs.h> /* /proc header file */
66 #include <sys/wait.h>
67 #include <locale.h>
68 #include <unistd.h>
69 #include <limits.h>
70 #include <priv_utils.h>
71
72 /*
73 * Use the full lengths from utmpx for user and line.
74 */
75 #define NMAX (sizeof (((struct utmpx *)0)->ut_user))
76 #define LMAX (sizeof (((struct utmpx *)0)->ut_line))
77
78 /* Print minimum field widths. */
79 #define LOGIN_WIDTH 8
80 #define LINE_WIDTH 12
81
82 #define DIV60(t) ((t+30)/60) /* x/60 rounded */
83
84 #ifdef ERR
85 #undef ERR
86 #endif
87 #define ERR (-1)
88
89 #define DEVNAMELEN 14
90 #define HSIZE 256 /* size of process hash table */
91 #define PROCDIR "/proc"
92 #define INITPROCESS (pid_t)1 /* init process pid */
93 #define NONE 'n' /* no state */
94 #define RUNNING 'r' /* runnable process */
95 #define ZOMBIE 'z' /* zombie process */
96 #define VISITED 'v' /* marked node as visited */
97
98 static int ndevs; /* number of configured devices */
99 static int maxdev; /* slots for configured devices */
100 #define DNINCR 100
116 *p_sibling, /* sibling pointer */
117 *p_pgrplink, /* pgrp link */
118 *p_link; /* hash table chain pointer */
119 };
120
121 /*
122 * define hash table for struct uproc
123 * Hash function uses process id
124 * and the size of the hash table(HSIZE)
125 * to determine process index into the table.
126 */
127 static struct uproc pr_htbl[HSIZE];
128
129 static struct uproc *findhash(pid_t);
130 static time_t findidle(char *);
131 static void clnarglist(char *);
132 static void showproc(struct uproc *);
133 static void showtotals(struct uproc *);
134 static void calctotals(struct uproc *);
135 static char *getty(dev_t);
136 static void prttime(time_t, char *);
137 static void prtat(time_t *);
138 static void checkampm(char *);
139
140 static char *prog;
141 static int header = 1; /* true if -h flag: don't print heading */
142 static int lflag = 0; /* true if -l flag: w command format */
143 static char *sel_user; /* login of particular user selected */
144 static time_t now; /* current time of day */
145 static time_t uptime; /* time of last reboot & elapsed time since */
146 static int nusers; /* number of users logged in now */
147 static time_t idle; /* number of minutes user is idle */
148 static time_t jobtime; /* total cpu time visible */
149 static char doing[520]; /* process attached to terminal */
150 static time_t proctime; /* cpu time of process in doing */
151 static int empty;
152 static pid_t curpid;
153
154 #if SIGQUIT > SIGINT
155 #define ACTSIZE SIGQUIT
156 #else
157 #define ACTSIZE SIGINT
158 #endif
256 endutxent();
257
258 (void) time(&now); /* get current time */
259
260 if (header) { /* print a header */
261 if (lflag) { /* w command format header */
262 prtat(&now);
263 for (ut = utmpbegin; ut < utmpend; ut++) {
264 if (ut->ut_type == USER_PROCESS) {
265 nusers++;
266 } else if (ut->ut_type == BOOT_TIME) {
267 uptime = now - ut->ut_xtime;
268 uptime += 30;
269 days = uptime / (60*60*24);
270 uptime %= (60*60*24);
271 hrs = uptime / (60*60);
272 uptime %= (60*60);
273 mins = uptime / 60;
274
275 (void) printf(dcgettext(NULL,
276 " up %d day(s), %d hr(s), "
277 "%d min(s)", LC_TIME),
278 days, hrs, mins);
279 }
280 }
281
282 ut = utmpbegin; /* rewind utmp data */
283 (void) printf(dcgettext(NULL,
284 " %d user(s)\n", LC_TIME), nusers);
285 (void) printf(dcgettext(NULL, "User tty "
286 "login@ idle JCPU PCPU what\n", LC_TIME));
287 } else { /* standard whodo header */
288 char date_buf[100];
289
290 /*
291 * print current time and date
292 */
293 (void) strftime(date_buf, sizeof (date_buf),
294 dcgettext(NULL, "%C", LC_TIME), localtime(&now));
295 (void) printf("%s\n", date_buf);
296
297 /*
298 * print system name
299 */
300 (void) uname(&uts);
301 (void) printf("%s\n", uts.nodename);
302 }
303 }
304
305 /*
306 * loop through /proc, reading info about each process
307 * and build the parent/child tree
308 */
309 if (!(dirp = opendir(PROCDIR))) {
310 (void) fprintf(stderr, gettext("%s: could not open %s: %s\n"),
311 prog, PROCDIR, strerror(errno));
312 exit(1);
313 }
314
457 (void) closedir(dirp);
458 (void) time(&now); /* get current time */
459
460 /*
461 * loop through utmpx file, printing process info
462 * about each logged in user
463 */
464 for (ut = utmpbegin; ut < utmpend; ut++) {
465 time_t tim;
466
467 if (ut->ut_type != USER_PROCESS)
468 continue;
469 if (sel_user && strncmp(ut->ut_name, sel_user, NMAX) != 0)
470 continue; /* we're looking for somebody else */
471 if (lflag) { /* -l flag format (w command) */
472 /* print login name of the user */
473 (void) printf("%-*.*s ", LOGIN_WIDTH, (int)NMAX,
474 ut->ut_name);
475
476 /* print tty user is on */
477 (void) printf("%-*.*s", LINE_WIDTH, (int)LMAX,
478 ut->ut_line);
479
480 /* print when the user logged in */
481 tim = ut->ut_xtime;
482 (void) prtat(&tim);
483
484 /* print idle time */
485 idle = findidle(ut->ut_line);
486 if (idle >= 36 * 60)
487 (void) printf(dcgettext(NULL, "%2ddays ",
488 LC_TIME), (idle + 12 * 60) / (24 * 60));
489 else
490 prttime(idle, " ");
491 showtotals(findhash((pid_t)ut->ut_pid));
492 } else { /* standard whodo format */
493 tim = ut->ut_xtime;
494 tm = localtime(&tim);
495 (void) printf("\n%-*.*s %-*.*s %2.1d:%2.2d\n",
496 LINE_WIDTH, (int)LMAX, ut->ut_line,
497 LOGIN_WIDTH, (int)NMAX, ut->ut_name, tm->tm_hour,
498 tm->tm_min);
499 showproc(findhash((pid_t)ut->ut_pid));
500 }
501 }
502
503 return (0);
504 }
505
506 /*
507 * Used for standard whodo format.
508 * This is the recursive routine descending the process
509 * tree starting from the given process pointer(up).
510 * It used depth-first search strategy and also marked
545
546
547 /*
548 * Used for -l flag (w command) format.
549 * Prints the CPU time for all processes & children,
550 * and the cpu time for interesting process,
551 * and what the user is doing.
552 */
553 static void
554 showtotals(struct uproc *up)
555 {
556 jobtime = 0;
557 proctime = 0;
558 empty = 1;
559 curpid = -1;
560 (void) strcpy(doing, "-"); /* default act: normally never prints */
561 calctotals(up);
562
563 /* print CPU time for all processes & children */
564 /* and need to convert clock ticks to seconds first */
565 prttime((time_t)jobtime, " ");
566
567 /* print cpu time for interesting process */
568 /* and need to convert clock ticks to seconds first */
569 prttime((time_t)proctime, " ");
570
571 /* what user is doing, current process */
572 (void) printf(" %-.32s\n", doing);
573 }
574
575 /*
576 * Used for -l flag (w command) format.
577 * This recursive routine descends the process
578 * tree starting from the given process pointer(up).
579 * It used depth-first search strategy and also marked
580 * each node as visited as it traversed down the tree.
581 * It calculates the process time for all processes &
582 * children. It also finds the "interesting" process
583 * and determines its cpu time and command.
584 */
585 static void
586 calctotals(struct uproc *up)
587 {
588 struct uproc *zp;
589
590 if (up->p_state == VISITED)
591 return;
592 up->p_state = VISITED;
719 }
720 }
721 tp = malloc(sizeof (*tp)); /* add new node */
722 if (!tp) {
723 (void) fprintf(stderr, gettext("%s: out of memory!: %s\n"),
724 prog, strerror(errno));
725 exit(1);
726 }
727 (void) memset((char *)tp, 0, sizeof (*tp));
728 tp->p_upid = pid;
729 tp->p_state = NONE;
730 tp->p_child = tp->p_sibling = tp->p_pgrplink = (pid_t)0;
731 tp->p_link = up->p_link; /* insert after head */
732 up->p_link = tp;
733 return (tp);
734 }
735
736 #define HR (60 * 60)
737 #define DAY (24 * HR)
738 #define MON (30 * DAY)
739
740 /*
741 * prints a time in hours and minutes or minutes and seconds.
742 * The character string 'tail' is printed at the end, obvious
743 * strings to pass are "", " ", or "am".
744 */
745 static void
746 prttime(time_t tim, char *tail)
747 {
748 if (tim >= 60)
749 (void) printf(dcgettext(NULL, "%3d:%02d", LC_TIME),
750 (int)tim/60, (int)tim%60);
751 else if (tim > 0)
752 (void) printf(dcgettext(NULL, " %2d", LC_TIME), (int)tim);
753 else
754 (void) printf(" ");
755 (void) printf("%s", tail);
756 }
757
758
759 /*
760 * prints a 12 hour time given a pointer to a time of day
761 */
762 static void
763 prtat(time_t *time)
764 {
765 struct tm *p;
766
767 p = localtime(time);
768 if (now - *time <= 18 * HR) {
769 char timestr[50];
770 (void) strftime(timestr, sizeof (timestr),
771 dcgettext(NULL, " %l:%M""%p", LC_TIME), p);
772 checkampm(timestr);
773 (void) printf("%s", timestr);
774 } else if (now - *time <= 7 * DAY) {
775 char weekdaytime[20];
776
777 (void) strftime(weekdaytime, sizeof (weekdaytime),
778 dcgettext(NULL, "%a%l%p", LC_TIME), p);
779 checkampm(weekdaytime);
780 (void) printf(" %s", weekdaytime);
781 } else {
782 char monthtime[20];
783
784 (void) strftime(monthtime, sizeof (monthtime),
785 dcgettext(NULL, "%e%b%y", LC_TIME), p);
786 (void) printf(" %s", monthtime);
787 }
788 }
789
790 /*
791 * find & return number of minutes current tty has been idle
792 */
793 static time_t
794 findidle(char *devname)
795 {
796 struct stat stbuf;
797 time_t lastaction, diff;
798 char ttyname[64];
799
800 (void) strcpy(ttyname, "/dev/");
801 (void) strcat(ttyname, devname);
802 if (stat(ttyname, &stbuf) != -1) {
803 lastaction = stbuf.st_atime;
804 diff = now - lastaction;
805 diff = DIV60(diff);
806 if (diff < 0)
813 /*
814 * given a pointer to the argument string clean out unsavory characters.
815 */
816 static void
817 clnarglist(char *arglist)
818 {
819 char *c;
820 int err = 0;
821
822 /* get rid of unsavory characters */
823 for (c = arglist; *c == NULL; c++) {
824 if ((*c < ' ') || (*c > 0176)) {
825 if (err++ > 5) {
826 *arglist = NULL;
827 break;
828 }
829 *c = '?';
830 }
831 }
832 }
833
834 /* replaces all occurences of AM/PM with am/pm */
835 static void
836 checkampm(char *str)
837 {
838 char *ampm;
839 while ((ampm = strstr(str, "AM")) != NULL ||
840 (ampm = strstr(str, "PM")) != NULL) {
841 *ampm = tolower(*ampm);
842 *(ampm+1) = tolower(*(ampm+1));
843 }
844 }
|
60 #include <utmpx.h>
61 #include <sys/utsname.h>
62 #include <sys/stat.h>
63 #include <sys/mkdev.h>
64 #include <dirent.h>
65 #include <procfs.h> /* /proc header file */
66 #include <sys/wait.h>
67 #include <locale.h>
68 #include <unistd.h>
69 #include <limits.h>
70 #include <priv_utils.h>
71
72 /*
73 * Use the full lengths from utmpx for user and line.
74 */
75 #define NMAX (sizeof (((struct utmpx *)0)->ut_user))
76 #define LMAX (sizeof (((struct utmpx *)0)->ut_line))
77
78 /* Print minimum field widths. */
79 #define LOGIN_WIDTH 8
80 #define LINE_WIDTH 8
81
82 #define DIV60(t) ((t+30)/60) /* x/60 rounded */
83
84 #ifdef ERR
85 #undef ERR
86 #endif
87 #define ERR (-1)
88
89 #define DEVNAMELEN 14
90 #define HSIZE 256 /* size of process hash table */
91 #define PROCDIR "/proc"
92 #define INITPROCESS (pid_t)1 /* init process pid */
93 #define NONE 'n' /* no state */
94 #define RUNNING 'r' /* runnable process */
95 #define ZOMBIE 'z' /* zombie process */
96 #define VISITED 'v' /* marked node as visited */
97
98 static int ndevs; /* number of configured devices */
99 static int maxdev; /* slots for configured devices */
100 #define DNINCR 100
116 *p_sibling, /* sibling pointer */
117 *p_pgrplink, /* pgrp link */
118 *p_link; /* hash table chain pointer */
119 };
120
121 /*
122 * define hash table for struct uproc
123 * Hash function uses process id
124 * and the size of the hash table(HSIZE)
125 * to determine process index into the table.
126 */
127 static struct uproc pr_htbl[HSIZE];
128
129 static struct uproc *findhash(pid_t);
130 static time_t findidle(char *);
131 static void clnarglist(char *);
132 static void showproc(struct uproc *);
133 static void showtotals(struct uproc *);
134 static void calctotals(struct uproc *);
135 static char *getty(dev_t);
136 static void prttime(time_t, int);
137 static void prtat(time_t *);
138
139 static char *prog;
140 static int header = 1; /* true if -h flag: don't print heading */
141 static int lflag = 0; /* true if -l flag: w command format */
142 static char *sel_user; /* login of particular user selected */
143 static time_t now; /* current time of day */
144 static time_t uptime; /* time of last reboot & elapsed time since */
145 static int nusers; /* number of users logged in now */
146 static time_t idle; /* number of minutes user is idle */
147 static time_t jobtime; /* total cpu time visible */
148 static char doing[520]; /* process attached to terminal */
149 static time_t proctime; /* cpu time of process in doing */
150 static int empty;
151 static pid_t curpid;
152
153 #if SIGQUIT > SIGINT
154 #define ACTSIZE SIGQUIT
155 #else
156 #define ACTSIZE SIGINT
157 #endif
255 endutxent();
256
257 (void) time(&now); /* get current time */
258
259 if (header) { /* print a header */
260 if (lflag) { /* w command format header */
261 prtat(&now);
262 for (ut = utmpbegin; ut < utmpend; ut++) {
263 if (ut->ut_type == USER_PROCESS) {
264 nusers++;
265 } else if (ut->ut_type == BOOT_TIME) {
266 uptime = now - ut->ut_xtime;
267 uptime += 30;
268 days = uptime / (60*60*24);
269 uptime %= (60*60*24);
270 hrs = uptime / (60*60);
271 uptime %= (60*60);
272 mins = uptime / 60;
273
274 (void) printf(dcgettext(NULL,
275 "up %d day(s), %d hr(s), "
276 "%d min(s)", LC_TIME),
277 days, hrs, mins);
278 }
279 }
280
281 ut = utmpbegin; /* rewind utmp data */
282 (void) printf(dcgettext(NULL,
283 " %d user(s)\n", LC_TIME), nusers);
284 (void) printf(dcgettext(NULL, "User tty "
285 "login@ idle JCPU PCPU what\n",
286 LC_TIME));
287 } else { /* standard whodo header */
288 char date_buf[100];
289
290 /*
291 * print current time and date
292 */
293 (void) strftime(date_buf, sizeof (date_buf),
294 "%c", localtime(&now));
295 (void) printf("%s\n", date_buf);
296
297 /*
298 * print system name
299 */
300 (void) uname(&uts);
301 (void) printf("%s\n", uts.nodename);
302 }
303 }
304
305 /*
306 * loop through /proc, reading info about each process
307 * and build the parent/child tree
308 */
309 if (!(dirp = opendir(PROCDIR))) {
310 (void) fprintf(stderr, gettext("%s: could not open %s: %s\n"),
311 prog, PROCDIR, strerror(errno));
312 exit(1);
313 }
314
457 (void) closedir(dirp);
458 (void) time(&now); /* get current time */
459
460 /*
461 * loop through utmpx file, printing process info
462 * about each logged in user
463 */
464 for (ut = utmpbegin; ut < utmpend; ut++) {
465 time_t tim;
466
467 if (ut->ut_type != USER_PROCESS)
468 continue;
469 if (sel_user && strncmp(ut->ut_name, sel_user, NMAX) != 0)
470 continue; /* we're looking for somebody else */
471 if (lflag) { /* -l flag format (w command) */
472 /* print login name of the user */
473 (void) printf("%-*.*s ", LOGIN_WIDTH, (int)NMAX,
474 ut->ut_name);
475
476 /* print tty user is on */
477 (void) printf("%-*.*s ", LINE_WIDTH, (int)LMAX,
478 ut->ut_line);
479
480 /* print when the user logged in */
481 tim = ut->ut_xtime;
482 (void) prtat(&tim);
483
484 /* print idle time */
485 idle = findidle(ut->ut_line);
486 prttime(idle, 8);
487 showtotals(findhash((pid_t)ut->ut_pid));
488 } else { /* standard whodo format */
489 tim = ut->ut_xtime;
490 tm = localtime(&tim);
491 (void) printf("\n%-*.*s %-*.*s %2.1d:%2.2d\n",
492 LINE_WIDTH, (int)LMAX, ut->ut_line,
493 LOGIN_WIDTH, (int)NMAX, ut->ut_name, tm->tm_hour,
494 tm->tm_min);
495 showproc(findhash((pid_t)ut->ut_pid));
496 }
497 }
498
499 return (0);
500 }
501
502 /*
503 * Used for standard whodo format.
504 * This is the recursive routine descending the process
505 * tree starting from the given process pointer(up).
506 * It used depth-first search strategy and also marked
541
542
543 /*
544 * Used for -l flag (w command) format.
545 * Prints the CPU time for all processes & children,
546 * and the cpu time for interesting process,
547 * and what the user is doing.
548 */
549 static void
550 showtotals(struct uproc *up)
551 {
552 jobtime = 0;
553 proctime = 0;
554 empty = 1;
555 curpid = -1;
556 (void) strcpy(doing, "-"); /* default act: normally never prints */
557 calctotals(up);
558
559 /* print CPU time for all processes & children */
560 /* and need to convert clock ticks to seconds first */
561 prttime((time_t)jobtime, 8);
562
563 /* print cpu time for interesting process */
564 /* and need to convert clock ticks to seconds first */
565 prttime((time_t)proctime, 8);
566
567 /* what user is doing, current process */
568 (void) printf("%-.32s\n", doing);
569 }
570
571 /*
572 * Used for -l flag (w command) format.
573 * This recursive routine descends the process
574 * tree starting from the given process pointer(up).
575 * It used depth-first search strategy and also marked
576 * each node as visited as it traversed down the tree.
577 * It calculates the process time for all processes &
578 * children. It also finds the "interesting" process
579 * and determines its cpu time and command.
580 */
581 static void
582 calctotals(struct uproc *up)
583 {
584 struct uproc *zp;
585
586 if (up->p_state == VISITED)
587 return;
588 up->p_state = VISITED;
715 }
716 }
717 tp = malloc(sizeof (*tp)); /* add new node */
718 if (!tp) {
719 (void) fprintf(stderr, gettext("%s: out of memory!: %s\n"),
720 prog, strerror(errno));
721 exit(1);
722 }
723 (void) memset((char *)tp, 0, sizeof (*tp));
724 tp->p_upid = pid;
725 tp->p_state = NONE;
726 tp->p_child = tp->p_sibling = tp->p_pgrplink = (pid_t)0;
727 tp->p_link = up->p_link; /* insert after head */
728 up->p_link = tp;
729 return (tp);
730 }
731
732 #define HR (60 * 60)
733 #define DAY (24 * HR)
734 #define MON (30 * DAY)
735 #define PRINTF(a) (void) printf a
736
737 /*
738 * Prttime prints an elapsed time in hours, minutes, or seconds,
739 * right-justified with the rightmost column always blank.
740 * The second argument is the minimum field width.
741 */
742 static void
743 prttime(time_t tim, int width)
744 {
745 char value[36];
746
747 if (tim >= 36 * 60) {
748 (void) snprintf(value, sizeof (value), "%d:%02d:%02d",
749 (int)tim / HR, (int)(tim % HR) / 60, (int)tim % 60);
750 } else if (tim >= 60) {
751 (void) snprintf(value, sizeof (value), "%d:%02d",
752 (int)tim / 60, (int)tim % 60);
753 } else if (tim > 0) {
754 (void) snprintf(value, sizeof (value), "%d", (int)tim);
755 } else {
756 (void) strcpy(value, "0");
757 }
758 width = (width > 2) ? width - 1 : 1;
759 PRINTF(("%*s ", width, value));
760 }
761
762 /*
763 * Prints the ISO date or time given a pointer to a time of day,
764 * left-justfied in a 12-character expanding field with the
765 * rightmost column always blank.
766 * Includes a dcgettext() override in case a message catalog is needed.
767 */
768 static void
769 prtat(time_t *time)
770 {
771 struct tm *p;
772
773 p = localtime(time);
774 if (now - *time <= 18 * HR) {
775 char timestr[50];
776
777 (void) strftime(timestr, sizeof (timestr),
778 dcgettext(NULL, "%T", LC_TIME), p);
779 PRINTF(("%-11s ", timestr));
780 } else if (now - *time <= 7 * DAY) {
781 char weekdaytime[20];
782
783 (void) strftime(weekdaytime, sizeof (weekdaytime),
784 dcgettext(NULL, "%a %H:%M", LC_TIME), p);
785 PRINTF(("%-11s ", weekdaytime));
786 } else {
787 char monthtime[20];
788
789 (void) strftime(monthtime, sizeof (monthtime),
790 dcgettext(NULL, "%F", LC_TIME), p);
791 PRINTF(("%-11s ", monthtime));
792 }
793 }
794
795 /*
796 * find & return number of minutes current tty has been idle
797 */
798 static time_t
799 findidle(char *devname)
800 {
801 struct stat stbuf;
802 time_t lastaction, diff;
803 char ttyname[64];
804
805 (void) strcpy(ttyname, "/dev/");
806 (void) strcat(ttyname, devname);
807 if (stat(ttyname, &stbuf) != -1) {
808 lastaction = stbuf.st_atime;
809 diff = now - lastaction;
810 diff = DIV60(diff);
811 if (diff < 0)
818 /*
819 * given a pointer to the argument string clean out unsavory characters.
820 */
821 static void
822 clnarglist(char *arglist)
823 {
824 char *c;
825 int err = 0;
826
827 /* get rid of unsavory characters */
828 for (c = arglist; *c == NULL; c++) {
829 if ((*c < ' ') || (*c > 0176)) {
830 if (err++ > 5) {
831 *arglist = NULL;
832 break;
833 }
834 *c = '?';
835 }
836 }
837 }
|