6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
22 /* All Rights Reserved */
23
24
25 /*
26 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
28 */
29
30 #pragma ident "%Z%%M% %I% %E% SMI"
31
32 /*
33 * This program analyzes information found in /var/adm/utmpx
34 *
35 * Additionally information is gathered from /etc/inittab
36 * if requested.
37 *
38 *
39 * Syntax:
40 *
41 * who am i Displays info on yourself
42 *
43 * who -a Displays information about All
44 * entries in /var/adm/utmpx
45 *
46 * who -b Displays info on last boot
47 *
48 * who -d Displays info on DEAD PROCESSES
49 *
50 * who -H Displays HEADERS for output
51 *
83 #include <fcntl.h>
84 #include <stdio.h>
85 #include <string.h>
86 #include <sys/types.h>
87 #include <unistd.h>
88 #include <stdlib.h>
89 #include <sys/stat.h>
90 #include <time.h>
91 #include <utmpx.h>
92 #include <locale.h>
93 #include <pwd.h>
94 #include <limits.h>
95
96 static void process(void);
97 static void ck_file(char *);
98 static void dump(void);
99
100 static struct utmpx *utmpp; /* pointer for getutxent() */
101
102 /*
103 * utmpx defines wider fields for user and line. For compatibility of output,
104 * we are limiting these to the old maximums in utmp. Define UTMPX_NAMELEN
105 * to use the full lengths.
106 */
107 #ifndef UTMPX_NAMELEN
108 /* XXX - utmp - fix name length */
109 #define NMAX (_POSIX_LOGIN_NAME_MAX - 1)
110 #define LMAX 12
111 #else /* UTMPX_NAMELEN */
112 #define NMAX (sizeof (utmpp->ut_user))
113 #define LMAX (sizeof (utmpp->ut_line))
114 #endif
115
116 static char comment[BUFSIZ]; /* holds inittab comment */
117 static char errmsg[BUFSIZ]; /* used in snprintf for errors */
118 static int fildes; /* file descriptor for inittab */
119 static int Hopt = 0; /* 1 = who -H */
120 static char *inittab; /* ptr to inittab contents */
121 static char *iinit; /* index into inittab */
122 static int justme = 0; /* 1 = who am i */
123 static struct tm *lptr; /* holds user login time */
124 static char *myname; /* pointer to invoker's name */
125 static char *mytty; /* holds device user is on */
126 static char nameval[sizeof (utmpp->ut_user) + 1]; /* invoker's name */
127 static int number = 8; /* number of users per -q line */
128 static int optcnt = 0; /* keeps count of options */
129 static char outbuf[BUFSIZ]; /* buffer for output */
130 static char *program; /* holds name of this program */
131 #ifdef XPG4
132 static int aopt = 0; /* 1 = who -a */
133 static int dopt = 0; /* 1 = who -d */
134 #endif /* XPG4 */
135 static int qopt = 0; /* 1 = who -q */
151 main(int argc, char **argv)
152 {
153 int goerr = 0; /* non-zero indicates cmd error */
154 int i;
155 int optsw; /* switch for while of getopt() */
156
157 (void) setlocale(LC_ALL, "");
158
159 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
160 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
161 #endif
162 (void) textdomain(TEXT_DOMAIN);
163
164 validtype[USER_PROCESS] = 1;
165 validtype[EMPTY] = 0;
166 stbufp = &stbuf;
167
168 /*
169 * Strip off path name of this command
170 */
171 for (i = strlen(argv[0]); i >= 0 && argv[0][i] != '/'; --i);
172 if (i >= 0)
173 argv[0] += i+1;
174 program = argv[0];
175
176 /*
177 * Buffer stdout for speed
178 */
179 setbuf(stdout, outbuf);
180
181 /*
182 * Retrieve options specified on command line
183 * XCU4 - add -m option
184 */
185 while ((optsw = getopt(argc, argv, "abdHlmn:pqrstTu")) != EOF) {
186 optcnt++;
187 switch (optsw) {
188
189 case 'a':
190 optcnt += 7;
191 validtype[BOOT_TIME] = 1;
492 /*
493 * Get and check user name
494 */
495 if (utmpp->ut_user[0] == '\0')
496 (void) strcpy(user, " .");
497 else {
498 (void) strncpy(user, utmpp->ut_user, sizeof (user));
499 user[sizeof (user) - 1] = '\0';
500 }
501 totlusrs++;
502
503 /*
504 * Do print in 'who -q' format
505 */
506 if (qopt) {
507 /*
508 * XCU4 - Use non user macro for correct user count
509 */
510 if (((totlusrs - 1) % number) == 0 && totlusrs > 1)
511 (void) printf("\n");
512 (void) printf("%-*s ", NMAX, user);
513 return;
514 }
515
516
517 pexit = (int)' ';
518 pterm = (int)' ';
519
520 /*
521 * Get exit info if applicable
522 */
523 if (utmpp->ut_type == RUN_LVL || utmpp->ut_type == DEAD_PROCESS) {
524 pterm = utmpp->ut_exit.e_termination;
525 pexit = utmpp->ut_exit.e_exit;
526 }
527
528 /*
529 * Massage ut_xtime field
530 */
531 lptr = localtime(&utmpp->ut_xtime);
532 (void) strftime(time_buf, sizeof (time_buf),
548 * XCU4 - only print + or - for user processes
549 */
550 if (Topt && (utmpp->ut_type == USER_PROCESS)) {
551 w = '-';
552 (void) strcpy(path, "/dev/");
553 (void) strncpy(path + 5, utmpp->ut_line,
554 sizeof (utmpp->ut_line));
555 path[5 + sizeof (utmpp->ut_line)] = '\0';
556
557 if ((rc = stat(path, stbufp)) == -1) w = '?';
558 else if ((stbufp->st_mode & S_IWOTH) ||
559 (stbufp->st_mode & S_IWGRP)) /* Check group & other */
560 w = '+';
561
562 } else
563 w = ' ';
564
565 /*
566 * Print the TERSE portion of the output
567 */
568 (void) printf("%-*s %c %-12s %s", NMAX, user, w, device, time_buf);
569
570 if (!terse) {
571 /*
572 * Stat device for idle time
573 * (Don't complain if you can't)
574 */
575 rc = -1;
576 if (utmpp->ut_type == USER_PROCESS) {
577 (void) strcpy(path, "/dev/");
578 (void) strncpy(path + 5, utmpp->ut_line,
579 sizeof (utmpp->ut_line));
580 path[5 + sizeof (utmpp->ut_line)] = '\0';
581 rc = stat(path, stbufp);
582 }
583 if (rc != -1) {
584 idle = timnow - stbufp->st_mtime;
585 hr = idle/3600;
586 min = (unsigned)(idle/60)%60;
587 if (hr == 0 && min == 0)
588 (void) printf(gettext(" . "));
609 if (utmpp->ut_type == DEAD_PROCESS) {
610 (void) printf(gettext(" id=%4.4s "),
611 utmpp->ut_id);
612 (void) printf(gettext("term=%-3d "), pterm);
613 (void) printf(gettext("exit=%d "), pexit);
614 } else if (utmpp->ut_type != INIT_PROCESS) {
615 /*
616 * Search for each entry in inittab
617 * string. Keep our place from
618 * search to search to try and
619 * minimize the work. Wrap once if needed
620 * for each entry.
621 */
622 wrap = 0;
623 /*
624 * Look for a line beginning with
625 * utmpp->ut_id
626 */
627 while ((rc = strncmp(utmpp->ut_id, iinit,
628 strcspn(iinit, ":"))) != 0) {
629 for (; *iinit != '\n'; iinit++);
630 iinit++;
631
632 /*
633 * Wrap once if necessary to
634 * find entry in inittab
635 */
636 if (*iinit == '\0') {
637 if (!wrap) {
638 iinit = inittab;
639 wrap = 1;
640 }
641 }
642 }
643
644 if (*iinit != '\0') {
645 /*
646 * We found our entry
647 */
648 for (iinit++; *iinit != '#' &&
649 *iinit != '\n'; iinit++);
650 if (*iinit == '#') {
651 for (iinit++; *iinit == ' ' ||
652 *iinit == '\t'; iinit++);
653 for (rc = 0; *iinit != '\n'; iinit++)
654 comment[rc++] = *iinit;
655 comment[rc] = '\0';
656 } else
657 (void) strcpy(comment, " ");
658
659 (void) printf(" %s", comment);
660 } else
661 iinit = inittab; /* Reset pointer */
662 }
663 if (utmpp->ut_type == INIT_PROCESS)
664 (void) printf(gettext(" id=%4.4s"), utmpp->ut_id);
665 }
666 #ifdef XPG4
667 else
668 if (dopt && utmpp->ut_type == DEAD_PROCESS) {
669 (void) printf(gettext("\tterm=%-3d "), pterm);
670 (void) printf(gettext("exit=%d "), pexit);
671 }
672 #endif /* XPG4 */
739 * we have have found ourselves
740 * in the utmp file and the entry
741 * is a user process, this is not
742 * meaningful otherwise
743 *
744 */
745
746 dump();
747 exit(0);
748 }
749 continue;
750 }
751
752 /*
753 * Print the line if we want it
754 */
755 if (validtype[utmpp->ut_type]) {
756 #ifdef XPG4
757 if (utmpp->ut_type == LOGIN_PROCESS) {
758 if ((utmpp->ut_line[0] == '\0') ||
759 (strcmp(utmpp->ut_user, "LOGIN") != 0))
760 continue;
761 }
762 #endif /* XPG4 */
763 dump();
764 }
765 } else {
766 (void) fprintf(stderr,
767 gettext("%s: Error --- entry has ut_type "
768 "of %d\n"), program, utmpp->ut_type);
769 (void) fprintf(stderr,
770 gettext(" when maximum is %d\n"), UTMAXTYPE);
771 }
772 }
773
774 /*
775 * If justme is set at this point than the utmp entry
776 * was not found.
777 */
778 if (justme) {
779 static struct utmpx utmpt;
|
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
22 /* All Rights Reserved */
23
24
25 /*
26 * Copyright (c) 2013 Gary Mills
27 *
28 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
29 * Use is subject to license terms.
30 */
31
32 /*
33 * This program analyzes information found in /var/adm/utmpx
34 *
35 * Additionally information is gathered from /etc/inittab
36 * if requested.
37 *
38 *
39 * Syntax:
40 *
41 * who am i Displays info on yourself
42 *
43 * who -a Displays information about All
44 * entries in /var/adm/utmpx
45 *
46 * who -b Displays info on last boot
47 *
48 * who -d Displays info on DEAD PROCESSES
49 *
50 * who -H Displays HEADERS for output
51 *
83 #include <fcntl.h>
84 #include <stdio.h>
85 #include <string.h>
86 #include <sys/types.h>
87 #include <unistd.h>
88 #include <stdlib.h>
89 #include <sys/stat.h>
90 #include <time.h>
91 #include <utmpx.h>
92 #include <locale.h>
93 #include <pwd.h>
94 #include <limits.h>
95
96 static void process(void);
97 static void ck_file(char *);
98 static void dump(void);
99
100 static struct utmpx *utmpp; /* pointer for getutxent() */
101
102 /*
103 * Use the full lengths from utmpx for user and line.
104 */
105 #define NMAX (sizeof (utmpp->ut_user))
106 #define LMAX (sizeof (utmpp->ut_line))
107
108 /* Print minimum field widths. */
109 #define LOGIN_WIDTH 8
110 #define LINE_WIDTH 12
111
112 static char comment[BUFSIZ]; /* holds inittab comment */
113 static char errmsg[BUFSIZ]; /* used in snprintf for errors */
114 static int fildes; /* file descriptor for inittab */
115 static int Hopt = 0; /* 1 = who -H */
116 static char *inittab; /* ptr to inittab contents */
117 static char *iinit; /* index into inittab */
118 static int justme = 0; /* 1 = who am i */
119 static struct tm *lptr; /* holds user login time */
120 static char *myname; /* pointer to invoker's name */
121 static char *mytty; /* holds device user is on */
122 static char nameval[sizeof (utmpp->ut_user) + 1]; /* invoker's name */
123 static int number = 8; /* number of users per -q line */
124 static int optcnt = 0; /* keeps count of options */
125 static char outbuf[BUFSIZ]; /* buffer for output */
126 static char *program; /* holds name of this program */
127 #ifdef XPG4
128 static int aopt = 0; /* 1 = who -a */
129 static int dopt = 0; /* 1 = who -d */
130 #endif /* XPG4 */
131 static int qopt = 0; /* 1 = who -q */
147 main(int argc, char **argv)
148 {
149 int goerr = 0; /* non-zero indicates cmd error */
150 int i;
151 int optsw; /* switch for while of getopt() */
152
153 (void) setlocale(LC_ALL, "");
154
155 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
156 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
157 #endif
158 (void) textdomain(TEXT_DOMAIN);
159
160 validtype[USER_PROCESS] = 1;
161 validtype[EMPTY] = 0;
162 stbufp = &stbuf;
163
164 /*
165 * Strip off path name of this command
166 */
167 for (i = strlen(argv[0]); i >= 0 && argv[0][i] != '/'; --i)
168 ;
169 if (i >= 0)
170 argv[0] += i+1;
171 program = argv[0];
172
173 /*
174 * Buffer stdout for speed
175 */
176 setbuf(stdout, outbuf);
177
178 /*
179 * Retrieve options specified on command line
180 * XCU4 - add -m option
181 */
182 while ((optsw = getopt(argc, argv, "abdHlmn:pqrstTu")) != EOF) {
183 optcnt++;
184 switch (optsw) {
185
186 case 'a':
187 optcnt += 7;
188 validtype[BOOT_TIME] = 1;
489 /*
490 * Get and check user name
491 */
492 if (utmpp->ut_user[0] == '\0')
493 (void) strcpy(user, " .");
494 else {
495 (void) strncpy(user, utmpp->ut_user, sizeof (user));
496 user[sizeof (user) - 1] = '\0';
497 }
498 totlusrs++;
499
500 /*
501 * Do print in 'who -q' format
502 */
503 if (qopt) {
504 /*
505 * XCU4 - Use non user macro for correct user count
506 */
507 if (((totlusrs - 1) % number) == 0 && totlusrs > 1)
508 (void) printf("\n");
509 (void) printf("%-*.*s ", LOGIN_WIDTH, NMAX, user);
510 return;
511 }
512
513
514 pexit = (int)' ';
515 pterm = (int)' ';
516
517 /*
518 * Get exit info if applicable
519 */
520 if (utmpp->ut_type == RUN_LVL || utmpp->ut_type == DEAD_PROCESS) {
521 pterm = utmpp->ut_exit.e_termination;
522 pexit = utmpp->ut_exit.e_exit;
523 }
524
525 /*
526 * Massage ut_xtime field
527 */
528 lptr = localtime(&utmpp->ut_xtime);
529 (void) strftime(time_buf, sizeof (time_buf),
545 * XCU4 - only print + or - for user processes
546 */
547 if (Topt && (utmpp->ut_type == USER_PROCESS)) {
548 w = '-';
549 (void) strcpy(path, "/dev/");
550 (void) strncpy(path + 5, utmpp->ut_line,
551 sizeof (utmpp->ut_line));
552 path[5 + sizeof (utmpp->ut_line)] = '\0';
553
554 if ((rc = stat(path, stbufp)) == -1) w = '?';
555 else if ((stbufp->st_mode & S_IWOTH) ||
556 (stbufp->st_mode & S_IWGRP)) /* Check group & other */
557 w = '+';
558
559 } else
560 w = ' ';
561
562 /*
563 * Print the TERSE portion of the output
564 */
565 (void) printf("%-*.*s %c %-12s %s", LOGIN_WIDTH, NMAX, user,
566 w, device, time_buf);
567
568 if (!terse) {
569 /*
570 * Stat device for idle time
571 * (Don't complain if you can't)
572 */
573 rc = -1;
574 if (utmpp->ut_type == USER_PROCESS) {
575 (void) strcpy(path, "/dev/");
576 (void) strncpy(path + 5, utmpp->ut_line,
577 sizeof (utmpp->ut_line));
578 path[5 + sizeof (utmpp->ut_line)] = '\0';
579 rc = stat(path, stbufp);
580 }
581 if (rc != -1) {
582 idle = timnow - stbufp->st_mtime;
583 hr = idle/3600;
584 min = (unsigned)(idle/60)%60;
585 if (hr == 0 && min == 0)
586 (void) printf(gettext(" . "));
607 if (utmpp->ut_type == DEAD_PROCESS) {
608 (void) printf(gettext(" id=%4.4s "),
609 utmpp->ut_id);
610 (void) printf(gettext("term=%-3d "), pterm);
611 (void) printf(gettext("exit=%d "), pexit);
612 } else if (utmpp->ut_type != INIT_PROCESS) {
613 /*
614 * Search for each entry in inittab
615 * string. Keep our place from
616 * search to search to try and
617 * minimize the work. Wrap once if needed
618 * for each entry.
619 */
620 wrap = 0;
621 /*
622 * Look for a line beginning with
623 * utmpp->ut_id
624 */
625 while ((rc = strncmp(utmpp->ut_id, iinit,
626 strcspn(iinit, ":"))) != 0) {
627 for (; *iinit != '\n'; iinit++)
628 ;
629 iinit++;
630
631 /*
632 * Wrap once if necessary to
633 * find entry in inittab
634 */
635 if (*iinit == '\0') {
636 if (!wrap) {
637 iinit = inittab;
638 wrap = 1;
639 }
640 }
641 }
642
643 if (*iinit != '\0') {
644 /*
645 * We found our entry
646 */
647 for (iinit++; *iinit != '#' &&
648 *iinit != '\n'; iinit++)
649 ;
650 if (*iinit == '#') {
651 for (iinit++; *iinit == ' ' ||
652 *iinit == '\t'; iinit++)
653 ;
654 for (rc = 0; *iinit != '\n'; iinit++)
655 comment[rc++] = *iinit;
656 comment[rc] = '\0';
657 } else
658 (void) strcpy(comment, " ");
659
660 (void) printf(" %s", comment);
661 } else
662 iinit = inittab; /* Reset pointer */
663 }
664 if (utmpp->ut_type == INIT_PROCESS)
665 (void) printf(gettext(" id=%4.4s"), utmpp->ut_id);
666 }
667 #ifdef XPG4
668 else
669 if (dopt && utmpp->ut_type == DEAD_PROCESS) {
670 (void) printf(gettext("\tterm=%-3d "), pterm);
671 (void) printf(gettext("exit=%d "), pexit);
672 }
673 #endif /* XPG4 */
740 * we have have found ourselves
741 * in the utmp file and the entry
742 * is a user process, this is not
743 * meaningful otherwise
744 *
745 */
746
747 dump();
748 exit(0);
749 }
750 continue;
751 }
752
753 /*
754 * Print the line if we want it
755 */
756 if (validtype[utmpp->ut_type]) {
757 #ifdef XPG4
758 if (utmpp->ut_type == LOGIN_PROCESS) {
759 if ((utmpp->ut_line[0] == '\0') ||
760 (strcmp(utmpp->ut_user,
761 "LOGIN") != 0))
762 continue;
763 }
764 #endif /* XPG4 */
765 dump();
766 }
767 } else {
768 (void) fprintf(stderr,
769 gettext("%s: Error --- entry has ut_type "
770 "of %d\n"), program, utmpp->ut_type);
771 (void) fprintf(stderr,
772 gettext(" when maximum is %d\n"), UTMAXTYPE);
773 }
774 }
775
776 /*
777 * If justme is set at this point than the utmp entry
778 * was not found.
779 */
780 if (justme) {
781 static struct utmpx utmpt;
|