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
26 * $FreeBSD: src/usr.bin/who/who.c,v 1.9.2.4 2002/12/21 00:44:58 tjr Exp $
27 * $DragonFly: src/usr.bin/who/who.c,v 1.7 2008/06/05 18:06:33 swildner Exp $
30 #include <sys/types.h>
31 #include <sys/ioctl.h>
33 #include <sys/sysctl.h>
49 static void print_boottime(void);
50 static void heading(void);
51 static void process_utmp(FILE *);
52 static void quick(FILE *);
53 static void row(struct utmp
*);
54 static int ttywidth(void);
55 static void usage(void);
56 static void whoami(FILE *);
58 static int bflag
; /* Show date and time of last reboot */
59 static int Hflag
; /* Write column headings */
60 static int mflag
; /* Show info about current terminal */
61 static int qflag
; /* "Quick" mode */
62 static int sflag
; /* Show name, line, time */
63 static int Tflag
; /* Show terminal state */
64 static int uflag
; /* Show idle time */
67 main(int argc
, char **argv
)
73 setlocale(LC_TIME
, "");
75 while ((ch
= getopt(argc
, argv
, "HTbmqsu")) != -1) {
77 case 'H': /* Write column headings */
80 case 'T': /* Show terminal state */
83 case 'b': /* Show time and date since last boot */
86 case 'm': /* Show info about current terminal */
89 case 'q': /* "Quick" mode */
92 case 's': /* Show name, line, time */
95 case 'u': /* Show idle time */
106 if (argc
>= 2 && strcmp(argv
[0], "am") == 0 &&
107 strcasecmp(argv
[1], "i") == 0) {
108 /* "who am i" or "who am I", equivalent to -m */
120 if ((fp
= fopen(file
, "r")) == NULL
)
146 fprintf(stderr
, "usage: who [-bHmqsTu] [am I] [file]\n");
153 struct timeval boottime
;
156 size
= sizeof(boottime
);
157 if (sysctlbyname("kern.boottime", &boottime
, &size
, NULL
, 0) != -1 &&
158 boottime
.tv_sec
!= 0) {
159 printf("%s", ctime(&boottime
.tv_sec
));
166 printf("%-*s ", UT_NAMESIZE
, "NAME");
169 printf("%-*s ", UT_LINESIZE
, "LINE");
170 printf("%-*s ", 12, "TIME");
173 printf("%-*s", UT_HOSTSIZE
, "FROM");
180 char buf
[80], tty
[sizeof(_PATH_DEV
) + UT_LINESIZE
];
183 static int d_first
= -1;
188 d_first
= (*nl_langinfo(D_MD_ORDER
) == 'd');
190 if (Tflag
|| uflag
) {
191 snprintf(tty
, sizeof(tty
), "%s%.*s", _PATH_DEV
,
192 UT_LINESIZE
, ut
->ut_line
);
193 if (stat(tty
, &sb
) == 0) {
194 state
= sb
.st_mode
& (S_IWOTH
|S_IWGRP
) ?
196 idle
= time(NULL
) - sb
.st_mtime
;
198 err(1, "Cannot open %s", tty
);
202 printf("%-*.*s ", UT_NAMESIZE
, UT_NAMESIZE
, ut
->ut_name
);
204 printf("%c ", state
);
205 printf("%-*.*s ", UT_LINESIZE
, UT_LINESIZE
, ut
->ut_line
);
206 tm
= localtime(&ut
->ut_time
);
207 strftime(buf
, sizeof(buf
), d_first
? "%e %b %R" : "%b %e %R", tm
);
208 printf("%-*s ", 12, buf
);
212 else if (idle
< 24 * 60 * 60)
213 printf("%02d:%02d ", (int)(idle
/ 60 / 60),
214 (int)(idle
/ 60 % 60));
218 if (*ut
->ut_host
!= '\0')
219 printf("(%.*s)", UT_HOSTSIZE
, ut
->ut_host
);
224 process_utmp(FILE *fp
)
228 while (fread(&ut
, sizeof(ut
), 1, fp
) == 1)
229 if (*ut
.ut_name
!= '\0')
241 while (fread(&ut
, sizeof(ut
), 1, fp
) == 1) {
242 if (*ut
.ut_name
== '\0')
244 printf("%-*.*s", UT_NAMESIZE
, UT_NAMESIZE
, ut
.ut_name
);
245 if (++col
< ncols
/ (UT_NAMESIZE
+ 1))
256 printf("# users = %d\n", num
);
264 const char *name
, *p
, *tty
;
266 if ((tty
= ttyname(STDIN_FILENO
)) == NULL
)
268 else if ((p
= strrchr(tty
, '/')) != NULL
)
271 /* Search utmp for our tty, dump first matching record. */
272 while (fread(&ut
, sizeof(ut
), 1, fp
) == 1)
273 if (*ut
.ut_name
!= '\0' && strncmp(ut
.ut_line
, tty
,
279 /* Not found; fill the utmp structure with the information we have. */
280 memset(&ut
, 0, sizeof(ut
));
281 if ((pwd
= getpwuid(getuid())) != NULL
)
285 strncpy(ut
.ut_name
, name
, UT_NAMESIZE
);
286 strncpy(ut
.ut_line
, tty
, UT_LINESIZE
);
298 if ((cols
= getenv("COLUMNS")) != NULL
&& *cols
!= '\0') {
300 width
= strtol(cols
, &ep
, 10);
301 if (errno
|| width
<= 0 || width
> INT_MAX
|| ep
== cols
||
303 warnx("invalid COLUMNS environment variable ignored");
307 if (ioctl(STDOUT_FILENO
, TIOCGWINSZ
, &ws
) != -1)