xref: /freebsd/usr.bin/rusers/rusers.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
1 /*-
2  * Copyright (c) 1993, John Brezak
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 static const char rcsid[] =
36   "$FreeBSD$";
37 #endif /* not lint */
38 
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/socket.h>
42 #include <err.h>
43 #include <netdb.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <strings.h>
47 #include <unistd.h>
48 #include <rpc/rpc.h>
49 #include <rpc/pmap_clnt.h>
50 #include <arpa/inet.h>
51 #include <rpcsvc/rnusers.h>
52 
53 #define MAX_INT 0x7fffffff
54 #define HOST_WIDTH 20
55 #define LINE_WIDTH 15
56 
57 int longopt;
58 int allopt;
59 
60 struct host_list {
61 	struct host_list *next;
62 	struct in_addr addr;
63 } *hosts;
64 
65 int
66 search_host(struct in_addr addr)
67 {
68 	struct host_list *hp;
69 
70 	if (!hosts)
71 		return(0);
72 
73 	for (hp = hosts; hp != NULL; hp = hp->next) {
74 		if (hp->addr.s_addr == addr.s_addr)
75 			return(1);
76 	}
77 	return(0);
78 }
79 
80 void
81 remember_host(struct in_addr addr)
82 {
83 	struct host_list *hp;
84 
85 	if (!(hp = (struct host_list *)malloc(sizeof(struct host_list))))
86 		errx(1, "no memory");
87 	hp->addr.s_addr = addr.s_addr;
88 	hp->next = hosts;
89 	hosts = hp;
90 }
91 
92 int
93 rusers_reply(char *replyp, struct sockaddr_in *raddrp)
94 {
95         int x, idle;
96         char date[32], idle_time[64], remote[64];
97         struct hostent *hp;
98         utmpidlearr *up = (utmpidlearr *)replyp;
99         char *host;
100         int days, hours, minutes, seconds;
101 
102 	if (search_host(raddrp->sin_addr))
103 		return(0);
104 
105         if (!allopt && !up->utmpidlearr_len)
106                 return(0);
107 
108         hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr,
109                            sizeof(struct in_addr), AF_INET);
110         if (hp)
111                 host = hp->h_name;
112         else
113                 host = inet_ntoa(raddrp->sin_addr);
114 
115         if (!longopt)
116                 printf("%-*s ", HOST_WIDTH, host);
117 
118         for (x = 0; x < up->utmpidlearr_len; x++) {
119                 strncpy(date,
120                         &(ctime((time_t *)&(up->utmpidlearr_val[x].ui_utmp.ut_time))[4]),
121                         sizeof(date)-1);
122 
123                 idle = up->utmpidlearr_val[x].ui_idle;
124                 sprintf(idle_time, "  :%02d", idle);
125                 if (idle == MAX_INT)
126                         strcpy(idle_time, "??");
127                 else if (idle == 0)
128                         strcpy(idle_time, "");
129                 else {
130                         seconds = idle;
131                         days = seconds/(60*60*24);
132                         seconds %= (60*60*24);
133                         hours = seconds/(60*60);
134                         seconds %= (60*60);
135                         minutes = seconds/60;
136                         seconds %= 60;
137                         if (idle > 60)
138                                 sprintf(idle_time, "%d:%02d",
139                                         minutes, seconds);
140                         if (idle >= (60*60))
141                                 sprintf(idle_time, "%d:%02d:%02d",
142                                         hours, minutes, seconds);
143                         if (idle >= (24*60*60))
144                                 sprintf(idle_time, "%d days, %d:%02d:%02d",
145                                         days, hours, minutes, seconds);
146                 }
147 
148                 strncpy(remote, up->utmpidlearr_val[x].ui_utmp.ut_host, sizeof(remote)-1);
149                 if (strlen(remote) != 0)
150                         sprintf(remote, "(%.16s)", up->utmpidlearr_val[x].ui_utmp.ut_host);
151 
152                 if (longopt)
153                         printf("%-8.8s %*s:%-*.*s %-12.12s  %6s %.18s\n",
154                                up->utmpidlearr_val[x].ui_utmp.ut_name,
155                                HOST_WIDTH, host,
156                                LINE_WIDTH, LINE_WIDTH, up->utmpidlearr_val[x].ui_utmp.ut_line,
157                                date,
158                                idle_time,
159                                remote
160                                );
161                 else
162                         printf("%s ",
163                                up->utmpidlearr_val[x].ui_utmp.ut_name);
164         }
165         if (!longopt)
166                 putchar('\n');
167 
168 	remember_host(raddrp->sin_addr);
169 	return(0);
170 }
171 
172 void
173 onehost(char *host)
174 {
175         utmpidlearr up;
176         CLIENT *rusers_clnt;
177         struct sockaddr_in addr;
178         struct hostent *hp;
179 		struct timeval tv;
180 
181         hp = gethostbyname(host);
182         if (hp == NULL)
183                 errx(1, "unknown host \"%s\"", host);
184 
185         rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_IDLE, "udp");
186         if (rusers_clnt == NULL)
187                 errx(1, "%s", clnt_spcreateerror(""));
188 
189 	bzero((char *)&up, sizeof(up));
190 	tv.tv_sec = 15;		/* XXX ?? */
191 	tv.tv_usec = 0;
192 	if (clnt_call(rusers_clnt, RUSERSPROC_NAMES, xdr_void, NULL, xdr_utmpidlearr, &up, tv) != RPC_SUCCESS)
193                 errx(1, "%s", clnt_sperror(rusers_clnt, ""));
194         addr.sin_addr.s_addr = *(int *)hp->h_addr;
195         rusers_reply((char *)&up, &addr);
196 }
197 
198 void
199 allhosts()
200 {
201 	utmpidlearr up;
202 	enum clnt_stat clnt_stat;
203 
204 	bzero((char *)&up, sizeof(up));
205 	clnt_stat = clnt_broadcast(RUSERSPROG, RUSERSVERS_IDLE, RUSERSPROC_NAMES,
206 				   xdr_void, NULL,
207 				   xdr_utmpidlearr, (char *)&up, rusers_reply);
208 	if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT)
209 		errx(1, "%s", clnt_sperrno(clnt_stat));
210 }
211 
212 static void
213 usage()
214 {
215         fprintf(stderr, "usage: rusers [-la] [hosts ...]\n");
216         exit(1);
217 }
218 
219 int
220 main(int argc, char *argv[])
221 {
222         int ch;
223 
224         while ((ch = getopt(argc, argv, "al")) != -1)
225 	        switch (ch) {
226                 case 'a':
227                         allopt++;
228                         break;
229                 case 'l':
230                         longopt++;
231                         break;
232                 default:
233                         usage();
234                         /*NOTREACHED*/
235                 }
236 
237         setlinebuf(stdout);
238 	if (argc == optind)
239 		allhosts();
240 	else {
241 		for (; optind < argc; optind++)
242 			(void) onehost(argv[optind]);
243 	}
244         exit(0);
245 }
246