]>
git.saurik.com Git - apple/shell_cmds.git/blob - who/who.c
da46ad77d9e4349d83f99c873ed6fdd6356d1cec
2 * Copyright (c) 2002 Tim J. Robbins.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 /* commented as FBSDID not needed for Tiger ......
29 __FBSDID("$FreeBSD: src/usr.bin/who/who.c,v 1.20 2003/10/26 05:05:48 peter Exp $");
32 #include <sys/types.h>
33 #include <sys/ioctl.h>
51 /* from utmp.h; used only for print formatting */
54 #define UT_HOSTSIZE 16
56 static void heading(void);
57 static void process_utmp(void);
58 static void process_wtmp();
59 static void quick(void);
60 static void row(const struct utmpx
*);
61 static int ttywidth(void);
62 static void usage(void);
63 static void whoami(void);
65 static int bflag
; /* date & time of last reboot */
66 static int dflag
; /* dead processes */
67 static int Hflag
; /* Write column headings */
68 static int lflag
; /* waiting to login */
69 static int mflag
; /* Show info about current terminal */
70 static int pflag
; /* Processes active & spawned by init */
71 static int qflag
; /* "Quick" mode */
72 static int rflag
; /* run-level of the init process */
73 static int sflag
; /* Show name, line, time */
74 static int tflag
; /* time of change to system clock */
75 static int Tflag
; /* Show terminal state */
76 static int uflag
; /* Show idle time */
78 #include <get_compat.h>
79 #else /* !__APPLE__ */
80 #define COMPAT_MODE(a,b) (1)
81 #endif /* __APPLE__ */
82 static int unix2003_std
;
85 main(int argc
, char *argv
[])
89 setlocale(LC_TIME
, "");
91 unix2003_std
= COMPAT_MODE("bin/who", "unix2003");
93 while ((ch
= getopt(argc
, argv
, "abdHlmpqrstTu")) != -1) {
96 case 'a': /* -b, -d, -l, -p, -r, -t, -T and -u */
97 bflag
= dflag
= lflag
= pflag
= 1;
98 rflag
= tflag
= Tflag
= uflag
= 1;
100 case 'b': /* date & time of last reboot */
103 case 'd': /* dead processes */
106 case 'H': /* Write column headings */
109 case 'l': /* waiting to login */
112 case 'm': /* Show info about current terminal */
115 case 'p': /* Processes active & spawned by init */
118 case 'q': /* "Quick" mode */
121 case 'r': /* run-level of the init process */
124 case 's': /* Show name, line, time */
127 case 't': /* time of change to system clock */
130 case 'T': /* Show terminal state */
133 case 'u': /* Show idle time */
144 if (argc
>= 2 && strcmp(argv
[0], "am") == 0 &&
145 (strcmp(argv
[1], "i") == 0 || strcmp(argv
[1], "I") == 0)) {
146 /* "who am i" or "who am I", equivalent to -m */
155 if (!utmpxname(*argv
) || !wtmpxname(*argv
))
169 /* read and process utmpx file for relevant options */
170 if( Tflag
|| uflag
|| !(bflag
|| dflag
|| lflag
|| pflag
|| rflag
) )
174 /* read and process wtmp file for relevant options */
175 if (bflag
|| dflag
|| lflag
|| pflag
|| rflag
) {
188 fprintf(stderr
, "usage: who [-abdHlmpqrstTu] [am I] [file]\n");
196 printf("%-*s ", UT_NAMESIZE
, "NAME");
199 printf("%-*s ", UT_LINESIZE
, "LINE");
200 printf("%-*s ", 12, "TIME");
203 if (unix2003_std
&& uflag
&& !Tflag
)
205 printf("%-*s", UT_HOSTSIZE
, "FROM");
210 row(const struct utmpx
*ut
)
212 char buf
[80], tty
[sizeof(_PATH_DEV
) + _UTX_LINESIZE
];
215 static int d_first
= -1;
218 char login_pidstr
[20];
221 d_first
= (*nl_langinfo(D_MD_ORDER
) == 'd');
223 if (Tflag
|| uflag
) {
224 snprintf(tty
, sizeof(tty
), "%s%.*s", _PATH_DEV
,
225 _UTX_LINESIZE
, ut
->ut_line
);
228 if (stat(tty
, &sb
) == 0) {
229 state
= sb
.st_mode
& (S_IWOTH
|S_IWGRP
) ?
231 idle
= time(NULL
) - sb
.st_mtime
;
233 if (unix2003_std
&& !Tflag
) {
234 /* uflag without Tflag */
236 snprintf(login_pidstr
,sizeof(login_pidstr
),
239 strcpy(login_pidstr
," ?");
244 printf("%-*.*s ", UT_NAMESIZE
, _UTX_USERSIZE
, ut
->ut_user
);
246 printf("%c ", state
);
247 printf("%-*.*s ", UT_LINESIZE
, _UTX_LINESIZE
, ut
->ut_line
);
248 t
= _time32_to_time(ut
->ut_tv
.tv_sec
);
250 strftime(buf
, sizeof(buf
), d_first
? "%e %b %R" : "%b %e %R", tm
);
251 printf("%-*s ", 12, buf
);
255 else if (idle
< 24 * 60 * 60)
256 printf("%02d:%02d ", (int)(idle
/ 60 / 60),
257 (int)(idle
/ 60 % 60));
260 if (unix2003_std
&& !Tflag
) {
261 printf("%s ", login_pidstr
);
264 if (*ut
->ut_host
!= '\0')
265 printf("(%.*s)", _UTX_HOSTSIZE
, ut
->ut_host
);
275 while ((ut
= getutxent()) != NULL
)
276 if (*ut
->ut_user
!= '\0' && ut
->ut_type
== USER_PROCESS
) {
281 /* For some options, process the wtmp file to generate output */
286 struct utmpx lboot_ut
;
287 int num
= 0; /* count of user entries */
289 setutxent_wtmp(0); /* zero means reverse chronological */
290 lboot_ut
.ut_type
= 0;
291 while (!lboot_ut
.ut_type
&& (ut
= getutxent_wtmp()) != NULL
) {
292 switch(ut
->ut_type
) {
295 strcpy(lboot_ut
.ut_user
, "reboot");
296 strcpy(lboot_ut
.ut_line
, "~");
308 if (bflag
&& lboot_ut
.ut_type
)
311 /* run level of the init process is unknown in BSD system. If multi
312 user, then display the highest run level. Else, no-op.
314 if (rflag
&& (num
> 1))
315 printf(" . run-level 3\n");
326 while ((ut
= getutxent()) != NULL
) {
327 if (*ut
->ut_user
== '\0' || ut
->ut_type
!= USER_PROCESS
)
329 printf("%-*.*s", UT_NAMESIZE
, _UTX_USERSIZE
, ut
->ut_user
);
330 if (++col
< ncols
/ (UT_NAMESIZE
+ 1))
341 printf("# users = %d\n", num
);
350 const char *name
, *p
, *tty
;
352 if ((tty
= ttyname(STDIN_FILENO
)) == NULL
)
354 else if ((p
= strrchr(tty
, '/')) != NULL
)
357 memset(&ut
, 0, sizeof(ut
));
358 strncpy(ut
.ut_line
, tty
, sizeof(ut
.ut_line
));
359 memcpy(ut
.ut_id
, tty
+ (strlen(tty
) - sizeof(ut
.ut_id
)), sizeof(ut
.ut_id
));
360 ut
.ut_type
= USER_PROCESS
;
361 /* Search utmp for our tty, dump first matching record. */
368 /* Not found; fill the utmpx structure with the information we have. */
369 if ((pwd
= getpwuid(getuid())) != NULL
)
373 strncpy(ut
.ut_user
, name
, _UTX_USERSIZE
);
374 ut
.ut_tv
.tv_sec
= _time_to_time32(time(NULL
));
385 if ((cols
= getenv("COLUMNS")) != NULL
&& *cols
!= '\0') {
387 width
= strtol(cols
, &ep
, 10);
388 if (errno
|| width
<= 0 || width
> INT_MAX
|| ep
== cols
||
390 warnx("invalid COLUMNS environment variable ignored");
394 if (ioctl(STDOUT_FILENO
, TIOCGWINSZ
, &ws
) != -1)