62 #include <sys/types.h>
63 #include <utmpx.h>
64 #include <sys/stat.h>
65 #include <dirent.h>
66 #include <procfs.h> /* /proc header file */
67 #include <locale.h>
68 #include <unistd.h>
69 #include <sys/loadavg.h>
70 #include <limits.h>
71 #include <priv_utils.h>
72
73 /*
74 * Use the full lengths from utmpx for user and line.
75 */
76 static struct utmpx dummy;
77 #define NMAX (sizeof (dummy.ut_user))
78 #define LMAX (sizeof (dummy.ut_line))
79
80 /* Print minimum field widths. */
81 #define LOGIN_WIDTH 8
82 #define LINE_WIDTH 12
83
84 #define DIV60(t) ((t+30)/60) /* x/60 rounded */
85
86 #ifdef ERR
87 #undef ERR
88 #endif
89 #define ERR (-1)
90
91 #define HSIZE 256 /* size of process hash table */
92 #define PROCDIR "/proc"
93 #define INITPROCESS (pid_t)1 /* init process pid */
94 #define NONE 'n' /* no state */
95 #define RUNNING 'r' /* runnable process */
96 #define ZOMBIE 'z' /* zombie process */
97 #define VISITED 'v' /* marked node as visited */
98 #define PRINTF(a) if (printf a < 0) { \
99 perror((gettext("%s: printf failed"), prog)); \
100 exit(1); }
101
102 struct uproc {
110 char p_args[PRARGSZ+1]; /* command line arguments */
111 struct uproc *p_child, /* first child pointer */
112 *p_sibling, /* sibling pointer */
113 *p_pgrpl, /* pgrp link */
114 *p_link; /* hash table chain pointer */
115 };
116
117 /*
118 * define hash table for struct uproc
119 * Hash function uses process id
120 * and the size of the hash table(HSIZE)
121 * to determine process index into the table.
122 */
123 static struct uproc pr_htbl[HSIZE];
124
125 static struct uproc *findhash(pid_t);
126 static time_t findidle(char *);
127 static void clnarglist(char *);
128 static void showtotals(struct uproc *);
129 static void calctotals(struct uproc *);
130 static void prttime(time_t, char *);
131 static void prtat(time_t *time);
132 static void checkampm(char *str);
133
134 static char *prog; /* pointer to invocation name */
135 static int header = 1; /* true if -h flag: don't print heading */
136 static int lflag = 1; /* set if -l flag; 0 for -s flag: short form */
137 static char *sel_user; /* login of particular user selected */
138 static char firstchar; /* first char of name of prog invoked as */
139 static int login; /* true if invoked as login shell */
140 static time_t now; /* current time of day */
141 static time_t uptime; /* time of last reboot & elapsed time since */
142 static int nusers; /* number of users logged in now */
143 static time_t idle; /* number of minutes user is idle */
144 static time_t jobtime; /* total cpu time visible */
145 static char doing[520]; /* process attached to terminal */
146 static time_t proctime; /* cpu time of process in doing */
147 static pid_t curpid, empty;
148 static int add_times; /* boolean: add the cpu times or not */
149
150 #if SIGQUIT > SIGINT
151 #define ACTSIZE SIGQUIT
152 #else
292 }
293 }
294 }
295
296 ut = utmpbegin; /* rewind utmp data */
297 PRINTF((((nusers == 1) ?
298 gettext(" %d user") : gettext(" %d users")), nusers));
299 /*
300 * Print 1, 5, and 15 minute load averages.
301 */
302 (void) getloadavg(loadavg, 3);
303 PRINTF((gettext(", load average: %.2f, %.2f, %.2f\n"),
304 loadavg[LOADAVG_1MIN], loadavg[LOADAVG_5MIN],
305 loadavg[LOADAVG_15MIN]));
306
307 if (firstchar == 'u') /* uptime command */
308 exit(0);
309
310 if (lflag) {
311 PRINTF((dcgettext(NULL, "User tty "
312 "login@ idle JCPU PCPU what\n", LC_TIME)));
313 } else {
314 PRINTF((dcgettext(NULL,
315 "User tty idle what\n", LC_TIME)));
316 }
317
318 if (fflush(stdout) == EOF) {
319 perror((gettext("%s: fflush failed\n"), prog));
320 exit(1);
321 }
322 }
323
324 /*
325 * loop through /proc, reading info about each process
326 * and build the parent/child tree
327 */
328 if (!(dirp = opendir(PROCDIR))) {
329 (void) fprintf(stderr, gettext("%s: could not open %s: %s\n"),
330 prog, PROCDIR, strerror(errno));
331 exit(1);
332 }
333
334 while ((dp = readdir(dirp)) != NULL) {
335 if (dp->d_name[0] == '.')
468 (void) __priv_relinquish();
469
470 (void) closedir(dirp);
471 (void) time(&now); /* get current time */
472
473 /*
474 * loop through utmpx file, printing process info
475 * about each logged in user
476 */
477 for (ut = utmpbegin; ut < utmpend; ut++) {
478 if (ut->ut_type != USER_PROCESS)
479 continue;
480 if (sel_user && strncmp(ut->ut_name, sel_user, NMAX) != 0)
481 continue; /* we're looking for somebody else */
482
483 /* print login name of the user */
484 PRINTF(("%-*.*s ", LOGIN_WIDTH, NMAX, ut->ut_name));
485
486 /* print tty user is on */
487 if (lflag) {
488 PRINTF(("%-*.*s", LINE_WIDTH, LMAX, ut->ut_line));
489 } else {
490 if (ut->ut_line[0] == 'p' && ut->ut_line[1] == 't' &&
491 ut->ut_line[2] == 's' && ut->ut_line[3] == '/') {
492 PRINTF(("%-*.3s", LMAX, &ut->ut_line[4]));
493 } else {
494 PRINTF(("%-*.*s", LINE_WIDTH, LMAX,
495 ut->ut_line));
496 }
497 }
498
499 /* print when the user logged in */
500 if (lflag) {
501 time_t tim = ut->ut_xtime;
502 prtat(&tim);
503 }
504
505 /* print idle time */
506 idle = findidle(ut->ut_line);
507 if (idle >= 36 * 60) {
508 PRINTF((dcgettext(NULL, "%2ddays ", LC_TIME),
509 (idle + 12 * 60) / (24 * 60)));
510 } else
511 prttime(idle, " ");
512 showtotals(findhash(ut->ut_pid));
513 }
514 if (fclose(stdout) == EOF) {
515 perror((gettext("%s: fclose failed"), prog));
516 exit(1);
517 }
518 return (0);
519 }
520
521 /*
522 * Prints the CPU time for all processes & children,
523 * and the cpu time for interesting process,
524 * and what the user is doing.
525 */
526 static void
527 showtotals(struct uproc *up)
528 {
529 jobtime = 0;
530 proctime = 0;
531 empty = 1;
532 curpid = -1;
533 add_times = 1;
534
535 calctotals(up);
536
537 if (lflag) {
538 /* print CPU time for all processes & children */
539 /* and need to convert clock ticks to seconds first */
540 prttime((time_t)jobtime, " ");
541
542 /* print cpu time for interesting process */
543 /* and need to convert clock ticks to seconds first */
544 prttime((time_t)proctime, " ");
545 }
546 /* what user is doing, current process */
547 PRINTF((" %-.32s\n", doing));
548 }
549
550 /*
551 * This recursive routine descends the process
552 * tree starting from the given process pointer(up).
553 * It used depth-first search strategy and also marked
554 * each node as visited as it traversed down the tree.
555 * It calculates the process time for all processes &
556 * children. It also finds the interesting process
557 * and determines its cpu time and command.
558 */
559 static void
560 calctotals(struct uproc *up)
561 {
562 struct uproc *zp;
563
564 /*
565 * Once a node has been visited, stop adding cpu times
566 * for its children so they don't get totalled twice.
567 * Still look for the interesting job for this utmp
629 tp = malloc(sizeof (*tp)); /* add new node */
630 if (!tp) {
631 (void) fprintf(stderr, gettext("%s: out of memory!: %s\n"),
632 prog, strerror(errno));
633 exit(1);
634 }
635 (void) memset(tp, 0, sizeof (*tp));
636 tp->p_upid = pid;
637 tp->p_state = NONE;
638 tp->p_child = tp->p_sibling = tp->p_pgrpl = 0;
639 tp->p_link = up->p_link; /* insert after head */
640 up->p_link = tp;
641 return (tp);
642 }
643
644 #define HR (60 * 60)
645 #define DAY (24 * HR)
646 #define MON (30 * DAY)
647
648 /*
649 * prttime prints a time in hours and minutes or minutes and seconds.
650 * The character string tail is printed at the end, obvious
651 * strings to pass are "", " ", or "am".
652 */
653 static void
654 prttime(time_t tim, char *tail)
655 {
656 if (tim >= 60) {
657 PRINTF((dcgettext(NULL, "%3d:%02d", LC_TIME),
658 (int)tim/60, (int)tim%60));
659 } else if (tim > 0) {
660 PRINTF((dcgettext(NULL, " %2d", LC_TIME), (int)tim));
661 } else {
662 PRINTF((" "));
663 }
664 PRINTF(("%s", tail));
665 }
666
667 /*
668 * prints a 12 hour time given a pointer to a time of day
669 */
670 static void
671 prtat(time_t *time)
672 {
673 struct tm *p;
674
675 p = localtime(time);
676 if (now - *time <= 18 * HR) {
677 char timestr[50];
678 (void) strftime(timestr, sizeof (timestr),
679 dcgettext(NULL, "%l:%M""%p", LC_TIME), p);
680 checkampm(timestr);
681 PRINTF((" %s", timestr));
682 } else if (now - *time <= 7 * DAY) {
683 char weekdaytime[20];
684
685 (void) strftime(weekdaytime, sizeof (weekdaytime),
686 dcgettext(NULL, "%a%l%p", LC_TIME), p);
687 checkampm(weekdaytime);
688 PRINTF((" %s", weekdaytime));
689 } else {
690 char monthtime[20];
691
692 (void) strftime(monthtime, sizeof (monthtime),
693 dcgettext(NULL, "%e%b%y", LC_TIME), p);
694 PRINTF((" %s", monthtime));
695 }
696 }
697
698 /*
699 * find & return number of minutes current tty has been idle
700 */
701 static time_t
702 findidle(char *devname)
703 {
704 struct stat stbuf;
705 time_t lastaction, diff;
706 char ttyname[64];
707
708 (void) strcpy(ttyname, "/dev/");
709 (void) strcat(ttyname, devname);
710 if (stat(ttyname, &stbuf) != -1) {
711 lastaction = stbuf.st_atime;
712 diff = now - lastaction;
713 diff = DIV60(diff);
714 if (diff < 0)
721 /*
722 * given a pointer to the argument string get rid of unsavory characters.
723 */
724 static void
725 clnarglist(char *arglist)
726 {
727 char *c;
728 int err = 0;
729
730 /* get rid of unsavory characters */
731 for (c = arglist; *c != NULL; c++) {
732 if ((*c < ' ') || (*c > 0176)) {
733 if (err++ > 5) {
734 *arglist = NULL;
735 break;
736 }
737 *c = '?';
738 }
739 }
740 }
741
742 /* replaces all occurences of AM/PM with am/pm */
743 static void
744 checkampm(char *str)
745 {
746 char *ampm;
747 while ((ampm = strstr(str, "AM")) != NULL ||
748 (ampm = strstr(str, "PM")) != NULL) {
749 *ampm = tolower(*ampm);
750 *(ampm+1) = tolower(*(ampm+1));
751 }
752 }
|
62 #include <sys/types.h>
63 #include <utmpx.h>
64 #include <sys/stat.h>
65 #include <dirent.h>
66 #include <procfs.h> /* /proc header file */
67 #include <locale.h>
68 #include <unistd.h>
69 #include <sys/loadavg.h>
70 #include <limits.h>
71 #include <priv_utils.h>
72
73 /*
74 * Use the full lengths from utmpx for user and line.
75 */
76 static struct utmpx dummy;
77 #define NMAX (sizeof (dummy.ut_user))
78 #define LMAX (sizeof (dummy.ut_line))
79
80 /* Print minimum field widths. */
81 #define LOGIN_WIDTH 8
82 #define LINE_WIDTH 8
83
84 #define DIV60(t) ((t+30)/60) /* x/60 rounded */
85
86 #ifdef ERR
87 #undef ERR
88 #endif
89 #define ERR (-1)
90
91 #define HSIZE 256 /* size of process hash table */
92 #define PROCDIR "/proc"
93 #define INITPROCESS (pid_t)1 /* init process pid */
94 #define NONE 'n' /* no state */
95 #define RUNNING 'r' /* runnable process */
96 #define ZOMBIE 'z' /* zombie process */
97 #define VISITED 'v' /* marked node as visited */
98 #define PRINTF(a) if (printf a < 0) { \
99 perror((gettext("%s: printf failed"), prog)); \
100 exit(1); }
101
102 struct uproc {
110 char p_args[PRARGSZ+1]; /* command line arguments */
111 struct uproc *p_child, /* first child pointer */
112 *p_sibling, /* sibling pointer */
113 *p_pgrpl, /* pgrp link */
114 *p_link; /* hash table chain pointer */
115 };
116
117 /*
118 * define hash table for struct uproc
119 * Hash function uses process id
120 * and the size of the hash table(HSIZE)
121 * to determine process index into the table.
122 */
123 static struct uproc pr_htbl[HSIZE];
124
125 static struct uproc *findhash(pid_t);
126 static time_t findidle(char *);
127 static void clnarglist(char *);
128 static void showtotals(struct uproc *);
129 static void calctotals(struct uproc *);
130 static void prttime(time_t, int);
131 static void prtat(time_t *time);
132
133 static char *prog; /* pointer to invocation name */
134 static int header = 1; /* true if -h flag: don't print heading */
135 static int lflag = 1; /* set if -l flag; 0 for -s flag: short form */
136 static char *sel_user; /* login of particular user selected */
137 static char firstchar; /* first char of name of prog invoked as */
138 static int login; /* true if invoked as login shell */
139 static time_t now; /* current time of day */
140 static time_t uptime; /* time of last reboot & elapsed time since */
141 static int nusers; /* number of users logged in now */
142 static time_t idle; /* number of minutes user is idle */
143 static time_t jobtime; /* total cpu time visible */
144 static char doing[520]; /* process attached to terminal */
145 static time_t proctime; /* cpu time of process in doing */
146 static pid_t curpid, empty;
147 static int add_times; /* boolean: add the cpu times or not */
148
149 #if SIGQUIT > SIGINT
150 #define ACTSIZE SIGQUIT
151 #else
291 }
292 }
293 }
294
295 ut = utmpbegin; /* rewind utmp data */
296 PRINTF((((nusers == 1) ?
297 gettext(" %d user") : gettext(" %d users")), nusers));
298 /*
299 * Print 1, 5, and 15 minute load averages.
300 */
301 (void) getloadavg(loadavg, 3);
302 PRINTF((gettext(", load average: %.2f, %.2f, %.2f\n"),
303 loadavg[LOADAVG_1MIN], loadavg[LOADAVG_5MIN],
304 loadavg[LOADAVG_15MIN]));
305
306 if (firstchar == 'u') /* uptime command */
307 exit(0);
308
309 if (lflag) {
310 PRINTF((dcgettext(NULL, "User tty "
311 "login@ idle JCPU PCPU what\n",
312 LC_TIME)));
313 } else {
314 PRINTF((dcgettext(NULL,
315 "User tty idle what\n",
316 LC_TIME)));
317 }
318
319 if (fflush(stdout) == EOF) {
320 perror((gettext("%s: fflush failed\n"), prog));
321 exit(1);
322 }
323 }
324
325 /*
326 * loop through /proc, reading info about each process
327 * and build the parent/child tree
328 */
329 if (!(dirp = opendir(PROCDIR))) {
330 (void) fprintf(stderr, gettext("%s: could not open %s: %s\n"),
331 prog, PROCDIR, strerror(errno));
332 exit(1);
333 }
334
335 while ((dp = readdir(dirp)) != NULL) {
336 if (dp->d_name[0] == '.')
469 (void) __priv_relinquish();
470
471 (void) closedir(dirp);
472 (void) time(&now); /* get current time */
473
474 /*
475 * loop through utmpx file, printing process info
476 * about each logged in user
477 */
478 for (ut = utmpbegin; ut < utmpend; ut++) {
479 if (ut->ut_type != USER_PROCESS)
480 continue;
481 if (sel_user && strncmp(ut->ut_name, sel_user, NMAX) != 0)
482 continue; /* we're looking for somebody else */
483
484 /* print login name of the user */
485 PRINTF(("%-*.*s ", LOGIN_WIDTH, NMAX, ut->ut_name));
486
487 /* print tty user is on */
488 if (lflag) {
489 PRINTF(("%-*.*s ", LINE_WIDTH, LMAX, ut->ut_line));
490 } else {
491 if (ut->ut_line[0] == 'p' && ut->ut_line[1] == 't' &&
492 ut->ut_line[2] == 's' && ut->ut_line[3] == '/') {
493 PRINTF(("%-*.*s ", LINE_WIDTH, LMAX,
494 &ut->ut_line[4]));
495 } else {
496 PRINTF(("%-*.*s ", LINE_WIDTH, LMAX,
497 ut->ut_line));
498 }
499 }
500
501 /* print when the user logged in */
502 if (lflag) {
503 time_t tim = ut->ut_xtime;
504 prtat(&tim);
505 }
506
507 /* print idle time */
508 idle = findidle(ut->ut_line);
509 prttime(idle, 8);
510 showtotals(findhash(ut->ut_pid));
511 }
512 if (fclose(stdout) == EOF) {
513 perror((gettext("%s: fclose failed"), prog));
514 exit(1);
515 }
516 return (0);
517 }
518
519 /*
520 * Prints the CPU time for all processes & children,
521 * and the cpu time for interesting process,
522 * and what the user is doing.
523 */
524 static void
525 showtotals(struct uproc *up)
526 {
527 jobtime = 0;
528 proctime = 0;
529 empty = 1;
530 curpid = -1;
531 add_times = 1;
532
533 calctotals(up);
534
535 if (lflag) {
536 /* print CPU time for all processes & children */
537 /* and need to convert clock ticks to seconds first */
538 prttime((time_t)jobtime, 8);
539
540 /* print cpu time for interesting process */
541 /* and need to convert clock ticks to seconds first */
542 prttime((time_t)proctime, 8);
543 }
544 /* what user is doing, current process */
545 PRINTF(("%-.32s\n", doing));
546 }
547
548 /*
549 * This recursive routine descends the process
550 * tree starting from the given process pointer(up).
551 * It used depth-first search strategy and also marked
552 * each node as visited as it traversed down the tree.
553 * It calculates the process time for all processes &
554 * children. It also finds the interesting process
555 * and determines its cpu time and command.
556 */
557 static void
558 calctotals(struct uproc *up)
559 {
560 struct uproc *zp;
561
562 /*
563 * Once a node has been visited, stop adding cpu times
564 * for its children so they don't get totalled twice.
565 * Still look for the interesting job for this utmp
627 tp = malloc(sizeof (*tp)); /* add new node */
628 if (!tp) {
629 (void) fprintf(stderr, gettext("%s: out of memory!: %s\n"),
630 prog, strerror(errno));
631 exit(1);
632 }
633 (void) memset(tp, 0, sizeof (*tp));
634 tp->p_upid = pid;
635 tp->p_state = NONE;
636 tp->p_child = tp->p_sibling = tp->p_pgrpl = 0;
637 tp->p_link = up->p_link; /* insert after head */
638 up->p_link = tp;
639 return (tp);
640 }
641
642 #define HR (60 * 60)
643 #define DAY (24 * HR)
644 #define MON (30 * DAY)
645
646 /*
647 * prttime prints a time in days, hours, minutes, or seconds.
648 * The second argument is the field width.
649 */
650 static void
651 prttime(time_t tim, int width)
652 {
653 char value[12];
654 char *unit;
655
656 if (tim >= 36 * HR) {
657 (void) snprintf(value, sizeof (value), "%d",
658 (tim + (DAY / 2)) / (DAY));
659 unit = dcgettext(NULL, "days", LC_TIME);
660 } else if (tim >= 36 * 60) {
661 (void) snprintf(value, sizeof (value), "%d",
662 (tim + (HR / 2)) / (HR));
663 unit = dcgettext(NULL, "hours", LC_TIME);
664 } else if (tim >= 60) {
665 (void) snprintf(value, sizeof (value), "%d",
666 (tim + 30) / 60);
667 unit = dcgettext(NULL, "mins", LC_TIME);
668 } else if (tim > 0) {
669 (void) snprintf(value, sizeof (value), "%d", (int)tim);
670 unit = dcgettext(NULL, "secs", LC_TIME);
671 } else {
672 (void) strcpy(value, "0");
673 unit = " ";
674 }
675 width -= 2 + strlen(value);
676 width = (width > 1) ? width : 1;
677 PRINTF(("%s %-*s ", value, width, unit));
678 }
679
680 /*
681 * prints a locale-specific time given a pointer to a time of day
682 */
683 static void
684 prtat(time_t *time)
685 {
686 struct tm *p;
687
688 p = localtime(time);
689 if (now - *time <= 18 * HR) {
690 char timestr[50];
691
692 (void) strftime(timestr, sizeof (timestr),
693 "%X", p);
694 PRINTF(("%-11s ", timestr));
695 } else if (now - *time <= 7 * DAY) {
696 char weekdaytime[20];
697
698 (void) strftime(weekdaytime, sizeof (weekdaytime),
699 "%d %b", p);
700 PRINTF(("%-11s ", weekdaytime));
701 } else {
702 char monthtime[20];
703
704 (void) strftime(monthtime, sizeof (monthtime),
705 "%b %Y", p);
706 PRINTF(("%-11s ", monthtime));
707 }
708 }
709
710 /*
711 * find & return number of minutes current tty has been idle
712 */
713 static time_t
714 findidle(char *devname)
715 {
716 struct stat stbuf;
717 time_t lastaction, diff;
718 char ttyname[64];
719
720 (void) strcpy(ttyname, "/dev/");
721 (void) strcat(ttyname, devname);
722 if (stat(ttyname, &stbuf) != -1) {
723 lastaction = stbuf.st_atime;
724 diff = now - lastaction;
725 diff = DIV60(diff);
726 if (diff < 0)
733 /*
734 * given a pointer to the argument string get rid of unsavory characters.
735 */
736 static void
737 clnarglist(char *arglist)
738 {
739 char *c;
740 int err = 0;
741
742 /* get rid of unsavory characters */
743 for (c = arglist; *c != NULL; c++) {
744 if ((*c < ' ') || (*c > 0176)) {
745 if (err++ > 5) {
746 *arglist = NULL;
747 break;
748 }
749 *c = '?';
750 }
751 }
752 }
|