1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1992-2012 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *               Glenn Fowler <glenn.s.fowler@gmail.com>                *
18 *                    David Korn <dgkorn@gmail.com>                     *
19 *                                                                      *
20 ***********************************************************************/
21 #pragma prototyped
22 /*
23  * who.c
24  * Written by David Korn
25  * Thu Aug 15 00:12:29 EDT 1996
26  */
27 
28 static const char usage[] =
29 "[-?\n@(#)$Id: who (AT&T Research) 2004-03-25 $\n]"
30 USAGE_LICENSE
31 "[+NAME?who - display who is on the system]"
32 "[+DESCRIPTION?\bwho\b displays various pieces of information about "
33 	"logged in users to standard output.]"
34 "[+?\bwho\b lists the user's name, terminal line, login time, and remote "
35 	"host name, if applicable, for each logged "
36 	"in user it reports.]"
37 "[+?The second form, \bwho am I\b is equivalent to \bwho -m\b.]"
38 
39 "[i:idle?Also writes the idle time for each displayed user.  The idle time "
40 	"is the time since last activity on that line.]"
41 "[m?Write only information about the current terminal.]"
42 "[q:count?Writes only the login names and the number of users logged on.  "
43 	"This options overrides other options.]"
44 "[s?This option is ignored.]"
45 "[u:?Equivalent to \b-i\b.]"
46 "[w:writable?Equivalent to \b-T\b.]"
47 "[H:heading?Put a heading line in before of the output.]"
48 "[T:mesg?Specifies the state of the terminal as one of the following:]{"
49 	"[++?The terminal allows write access to other users.]"
50 	"[+-?The terminal denies write access to other users.]"
51 	"[+???The write access cannot be determined.]"
52 	"}"
53 "\n"
54 "\n[am I]\n"
55 "\n"
56 "[+EXIT STATUS]{"
57 	"[+0?Successful completion.]"
58 	"[+>0?One or more errors occurred.]"
59 "}"
60 "[+SEE ALSO?\bdate\b(1), \blogin\b(1)]"
61 ;
62 
63 
64 #include	<cmd.h>
65 #include	<ls.h>
66 #include	<time.h>
67 
68 #include "FEATURE/utmp"
69 
70 #if _hdr_utmp
71 #	include	<utmp.h>
72 #endif
73 
74 #if _mem_ut_host_utmp && _mem_ut_type_utmp
75 #	undef	_hdr_utmpx
76 #endif
77 
78 #if _hdr_utmpx
79 #	include	<utmpx.h>
80 #	undef	_mem_ut_host_utmp
81 #	undef	_mem_ut_type_utmp
82 #	if _mem_ut_tv_utmpx
83 #		undef	ut_time
84 #		define	ut_time	ut_tv.tv_sec
85 #	endif
86 #	if ! _mem_ut_user_utmpx
87 #		define ut_user ut_name
88 #	endif
89 #	ifdef UTMPX_FILE
90 #		define UTMP	UTMPX_FILE
91 #	else
92 #		if _hdr_paths
93 #			include <paths.h>
94 #		endif
95 #		ifdef _PATH_UTMPX
96 #			define UTMP	_PATH_UTMPX
97 #		else
98 #			ifdef UTMP_FILE
99 #				define UTMP	UTMP_FILE
100 #			else
101 #				ifdef _PATH_UTMP
102 #					define UTMP	_PATH_UTMP
103 #				else
104 #					define UTMP	"/etc/utmpx"
105 #				endif
106 #			endif
107 #		endif
108 #	endif
109 #else
110 #	undef	_mem_ut_host_utmpx
111 #	undef	_mem_ut_type_utmpx
112 #	define utmpx	utmp
113 #	if _mem_ut_tv_utmp
114 #		undef	ut_time
115 #		define	ut_time	ut_tv.tv_sec
116 #	endif
117 #	if ! _mem_ut_user_utmp
118 #		define ut_user ut_name
119 #	endif
120 #	ifdef UTMP_FILE
121 #		define UTMP	UTMP_FILE
122 #	else
123 #		if _hdr_paths
124 #			include <paths.h>
125 #		endif
126 #		ifdef _PATH_UTMP
127 #			define UTMP	_PATH_UTMP
128 #		else
129 #			define UTMP	"/etc/utmp"
130 #		endif
131 #	endif
132 #endif
133 
134 #ifdef	nonuser
135 #	define dead(ut)	(nonuser(ut))
136 #else
137 #	if _mem_ut_type_utmp || _mem_ut_type_utmpx
138 #		ifdef USER_PROCESS
139 #			define dead(ut)		((ut).ut_type != USER_PROCESS)
140 #		else
141 #			ifndef	DEAD_PROCESS
142 #				define DEAD_PROCESS	8
143 #			endif
144 #			define dead(ut)		((ut).ut_type == DEAD_PROCESS)
145 #		endif
146 #	else
147 #		define dead(ut)	0
148 #	endif
149 #endif
150 
151 #define skip(ut)	(!*ut.ut_user||!*ut.ut_line||dead(ut)|!strcasecmp(ut.ut_user,"login"))
152 
153 typedef struct
154 {
155 	int	flags;
156 	int	siz_user;
157 	int	siz_line;
158 	int	siz_host;
159 } State_t;
160 
161 #define FLAG_M	1
162 #define FLAG_T	2
163 #define FLAG_U	4
164 #define FLAG_H	8
165 #define FLAG_Q	0x10
166 
outline(Sfio_t * out,register struct utmpx * up,register State_t * sp)167 static void outline(Sfio_t *out,register struct utmpx *up,register State_t* sp)
168 {
169 	struct stat statb;
170 	time_t t = up->ut_time;
171 	char *date = ctime(&t);
172 	char line[sizeof(up->ut_line)+6];
173 	int r = 0;
174 	if(sp->flags&(FLAG_T|FLAG_U))
175 	{
176 		sfsprintf(line,sizeof(line),"/dev/%s\0",up->ut_line);
177 		r = stat(line,&statb);
178 	}
179 	if(sp->flags&FLAG_T)
180 	{
181 		int state = '?';
182 		if(r>=0)
183 			state = (statb.st_mode&S_IWOTH)?'+':'-';
184 		sfprintf(out,"%-*.*s %c %-*.*s %.12s ",sp->siz_user,sp->siz_user,up->ut_user,state,sp->siz_line,sp->siz_line,up->ut_line,date+4);
185 	}
186 	else
187 		sfprintf(out,"%-*.*s %-*.*s %.12s ",sp->siz_user,sp->siz_user,up->ut_user,sp->siz_line,sp->siz_line,up->ut_line,date+4);
188 	if(sp->flags&FLAG_U)
189 	{
190 		time_t t = time(0)-30;
191 		sfsprintf(line,sizeof(line),"/dev/%s\0",up->ut_line);
192 		if(r>=0 && statb.st_atime<t)
193 		{
194 			t = (t-(up->ut_time+30))/60;
195 			if(t>24*60)
196 				sfprintf(out," old  ");
197 			else
198 				sfprintf(out, "%.2d:%.2d ",t/60,t%60);
199 		}
200 		else
201 			sfprintf(out,"  .   ");
202 	}
203 #if _mem_ut_host_utmp || _mem_ut_host_utmpx
204 	if (*up->ut_host)
205 		sfprintf(out,"  %-*.*s\n",sp->siz_host,sp->siz_host,up->ut_host);
206 	else
207 #endif
208 	sfputc(out,'\n');
209 }
210 
who(Sfio_t * in,Sfio_t * out,int flags)211 static int who(Sfio_t *in, Sfio_t *out, int flags)
212 {
213 	struct utmpx ut;
214 	char *line = 0;
215 	int count = 0;
216 	State_t state;
217 	state.flags = flags;
218 	state.siz_user = sizeof(ut.ut_user);
219 	if (state.siz_user > 24)
220 		state.siz_user = 24;
221 	state.siz_line = sizeof(ut.ut_line);
222 	if (state.siz_line > 8)
223 		state.siz_line = 8;
224 #if _mem_ut_host_utmp || _mem_ut_host_utmpx
225 	state.siz_host = sizeof(ut.ut_host);
226 	if (state.siz_host > 30)
227 		state.siz_host = 30;
228 #endif
229 	if(state.flags&FLAG_Q)
230 		state.flags = FLAG_Q;
231 	if((state.flags&FLAG_M) && ((line=ttyname(0)) || (line=ttyname(2))))
232 		line += 5;
233 	if(state.flags&FLAG_H)
234 	{
235 		char *t = "";
236 		if(state.flags&FLAG_T)
237 			t = "MESG";
238 		if(state.flags&FLAG_U)
239 			sfprintf(out,"%-*.*s %2s %-*.*s %.12s %6s     %s\n",state.siz_user-3,state.siz_user-3,"USER",t,state.siz_line,state.siz_line,"LINE","LOGIN-TIME","IDLE","FROM");
240 		else
241 			sfprintf(out,"%-*.*s %2s %-*.*s %.12s     %s\n",state.siz_user-3,state.siz_user-3,"USER",t,state.siz_line,state.siz_line,"LINE","LOGIN-TIME","FROM");
242 	}
243 	while(sfread(in,&ut,sizeof(struct utmpx))>0)
244 	{
245 		if(skip(ut))
246 			continue;
247 		if(line && strcmp(line,ut.ut_line))
248 			continue;
249 		if(state.flags&FLAG_Q)
250 		{
251 			if(count)
252 				sfputc(out,' ');
253 			sfprintf(out,"%s",ut.ut_user);
254 		}
255 		else
256 			outline(out,&ut,&state);
257 		count++;
258 	}
259 	if(state.flags&FLAG_Q)
260 		sfprintf(out,"\n# users=%d\n",count);
261 	return(0);
262 }
263 
b_who(int argc,char ** argv,Shbltin_t * context)264 int b_who(int argc, char** argv, Shbltin_t* context)
265 {
266 	register int n, flags=0;
267 	Sfio_t *sp;
268 
269 	cmdinit(argc, argv, context, ERROR_CATALOG, 0);
270 	while (n = optget(argv, usage)) switch (n)
271 	{
272 	    case 'm':
273 		flags |= FLAG_M;
274 		break;
275 	    case 'H':
276 		flags |= FLAG_H;
277 		break;
278 	    case 'T': case 'w':
279 		flags |= FLAG_T;
280 		break;
281 	    case 'q':
282 		flags |= FLAG_Q;
283 		break;
284 	    case 's':
285 		break;
286 	    case 'i':
287 	    case 'u':
288 		flags |= FLAG_U;
289 		break;
290 	    case ':':
291 		error(2, opt_info.arg);
292 		break;
293 	    case '?':
294 		error(ERROR_usage(2), "%s", opt_info.arg);
295 		break;
296 	}
297 	argv += opt_info.index;
298 	argc -= opt_info.index;
299 	if(argc==2)
300 	{
301 		flags |= FLAG_M;
302 		argc = 0;
303 	}
304 	if(error_info.errors || argc)
305 		error(ERROR_usage(2),"%s", optusage((char*)0));
306 	if(!(sp = sfopen((Sfio_t*)0,UTMP,"r")))
307 		error(ERROR_system(1),"%s: cannot open",UTMP);
308 	who(sp,sfstdout,flags);
309 	sfclose(sp);
310 	return(error_info.errors);
311 }
312