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