]>
git.saurik.com Git - apple/shell_cmds.git/blob - who/who.c
b700264473e9aa4ef5685e1f073c590589a47d26
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>
52 static void heading(void);
53 static void process_utmp(FILE *);
54 static void process_wtmp(FILE *);
55 static void quick(FILE *);
56 static void row(struct utmp
*);
57 static int ttywidth(void);
58 static void usage(void);
59 static void whoami(FILE *);
61 static int bflag
; /* date & time of last reboot */
62 static int dflag
; /* dead processes */
63 static int Hflag
; /* Write column headings */
64 static int lflag
; /* waiting to login */
65 static int mflag
; /* Show info about current terminal */
66 static int pflag
; /* Processes active & spawned by init */
67 static int qflag
; /* "Quick" mode */
68 static int rflag
; /* run-level of the init process */
69 static int sflag
; /* Show name, line, time */
70 static int tflag
; /* time of change to system clock */
71 static int Tflag
; /* Show terminal state */
72 static int uflag
; /* Show idle time */
74 #include <get_compat.h>
75 #else /* !__APPLE__ */
76 #define COMPAT_MODE(a,b) (1)
77 #endif /* __APPLE__ */
78 static int unix2003_std
;
79 static struct utmpx
*utx_db
= NULL
;
82 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 */
158 if ((fp
= fopen(file
, "r")) == NULL
)
171 /* read and process utmp file for relevant options */
172 if( Tflag
|| uflag
|| !(bflag
|| dflag
|| lflag
|| pflag
|| rflag
) )
178 /* read and process wtmp file for relevant options */
179 if (bflag
|| dflag
|| lflag
|| pflag
|| rflag
) {
181 /* Open the wtmp file */
182 if ((wtmp_fp
= fopen(_PATH_WTMP
, "r")) == NULL
)
183 err(1, "%s", _PATH_WTMP
);
185 process_wtmp(wtmp_fp
);
191 endutxent(); /* close db */
200 fprintf(stderr
, "usage: who [-abdHlmpqrstTu] [am I] [file]\n");
208 printf("%-*s ", UT_NAMESIZE
, "NAME");
211 printf("%-*s ", UT_LINESIZE
, "LINE");
212 printf("%-*s ", 12, "TIME");
215 if (unix2003_std
&& uflag
&& !Tflag
)
217 printf("%-*s", UT_HOSTSIZE
, "FROM");
224 char buf
[80], tty
[sizeof(_PATH_DEV
) + UT_LINESIZE
];
227 static int d_first
= -1;
230 char login_pidstr
[20];
233 d_first
= (*nl_langinfo(D_MD_ORDER
) == 'd');
235 if (Tflag
|| uflag
) {
236 snprintf(tty
, sizeof(tty
), "%s%.*s", _PATH_DEV
,
237 UT_LINESIZE
, ut
->ut_line
);
240 if (stat(tty
, &sb
) == 0) {
241 state
= sb
.st_mode
& (S_IWOTH
|S_IWGRP
) ?
243 idle
= time(NULL
) - sb
.st_mtime
;
245 if (unix2003_std
&& !Tflag
) {
246 /* uflag without Tflag */
247 struct utmpx
* utx
= NULL
;
249 utx_db
= getutxent(); /* just to open db */
252 struct utmpx this_line
;
253 setutxent(); /* reset db */
254 memset(&this_line
, 0, sizeof(this_line
));
256 strcpy(this_line.ut_user, ut->ut_name);
258 strcpy(this_line
.ut_line
, ut
->ut_line
);
259 utx
= getutxline(&this_line
);
262 snprintf(login_pidstr
,sizeof(login_pidstr
),
265 strcpy(login_pidstr
," ?");
270 printf("%-*.*s ", UT_NAMESIZE
, UT_NAMESIZE
, ut
->ut_name
);
272 printf("%c ", state
);
273 printf("%-*.*s ", UT_LINESIZE
, UT_LINESIZE
, ut
->ut_line
);
274 t
= _time32_to_time(ut
->ut_time
);
276 strftime(buf
, sizeof(buf
), d_first
? "%e %b %R" : "%b %e %R", tm
);
277 printf("%-*s ", 12, buf
);
281 else if (idle
< 24 * 60 * 60)
282 printf("%02d:%02d ", (int)(idle
/ 60 / 60),
283 (int)(idle
/ 60 % 60));
286 if (unix2003_std
&& !Tflag
) {
287 printf("%s ", login_pidstr
);
290 if (*ut
->ut_host
!= '\0')
291 printf("(%.*s)", UT_HOSTSIZE
, ut
->ut_host
);
297 process_utmp(FILE *fp
)
301 while (fread(&ut
, sizeof(ut
), 1, fp
) == 1)
302 if (*ut
.ut_name
!= '\0') {
307 /* For some options, process the wtmp file to generate output */
309 process_wtmp(FILE *fp
)
312 struct utmp lboot_ut
= { "", "", "", 0 };
313 int num
= 0; /* count of user entries */
315 while (fread(&ut
, sizeof(ut
), 1, fp
) == 1)
316 if (*ut
.ut_name
!= '\0') {
317 if (bflag
&& (!strcmp(ut
.ut_name
, "reboot"))) {
318 memcpy(&lboot_ut
, &ut
, sizeof(ut
));
324 if (bflag
&& (!strcmp(lboot_ut
.ut_name
, "reboot")))
327 /* run level of the init process is unknown in BSD system. If multi
328 user, then display the highest run level. Else, no-op.
330 if (rflag
&& (num
> 1))
331 printf(" . run-level 3\n");
342 while (fread(&ut
, sizeof(ut
), 1, fp
) == 1) {
343 if (*ut
.ut_name
== '\0')
345 printf("%-*.*s", UT_NAMESIZE
, UT_NAMESIZE
, ut
.ut_name
);
346 if (++col
< ncols
/ (UT_NAMESIZE
+ 1))
357 printf("# users = %d\n", num
);
365 const char *name
, *p
, *tty
;
367 if ((tty
= ttyname(STDIN_FILENO
)) == NULL
)
369 else if ((p
= strrchr(tty
, '/')) != NULL
)
372 /* Search utmp for our tty, dump first matching record. */
373 while (fread(&ut
, sizeof(ut
), 1, fp
) == 1)
374 if (*ut
.ut_name
!= '\0' && strncmp(ut
.ut_line
, tty
,
380 /* Not found; fill the utmp structure with the information we have. */
381 memset(&ut
, 0, sizeof(ut
));
382 if ((pwd
= getpwuid(getuid())) != NULL
)
386 strncpy(ut
.ut_name
, name
, UT_NAMESIZE
);
387 strncpy(ut
.ut_line
, tty
, UT_LINESIZE
);
388 ut
.ut_time
= _time_to_time32(time(NULL
));
399 if ((cols
= getenv("COLUMNS")) != NULL
&& *cols
!= '\0') {
401 width
= strtol(cols
, &ep
, 10);
402 if (errno
|| width
<= 0 || width
> INT_MAX
|| ep
== cols
||
404 warnx("invalid COLUMNS environment variable ignored");
408 if (ioctl(STDOUT_FILENO
, TIOCGWINSZ
, &ws
) != -1)