12345Scsgr/*-
22345Scsgr * Copyright (c) 1993, John Brezak
32345Scsgr * All rights reserved.
42345Scsgr *
52345Scsgr * Redistribution and use in source and binary forms, with or without
62345Scsgr * modification, are permitted provided that the following conditions
72345Scsgr * are met:
82345Scsgr * 1. Redistributions of source code must retain the above copyright
92345Scsgr *    notice, this list of conditions and the following disclaimer.
102345Scsgr * 2. Redistributions in binary form must reproduce the above copyright
112345Scsgr *    notice, this list of conditions and the following disclaimer in the
122345Scsgr *    documentation and/or other materials provided with the distribution.
132345Scsgr * 3. All advertising materials mentioning features or use of this software
142345Scsgr *    must display the following acknowledgement:
152345Scsgr *	This product includes software developed by the University of
162345Scsgr *	California, Berkeley and its contributors.
172345Scsgr * 4. Neither the name of the University nor the names of its contributors
182345Scsgr *    may be used to endorse or promote products derived from this software
192345Scsgr *    without specific prior written permission.
202345Scsgr *
212345Scsgr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
222345Scsgr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
232345Scsgr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
242345Scsgr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
252345Scsgr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
262345Scsgr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
272345Scsgr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
282345Scsgr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
292345Scsgr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
302345Scsgr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
312345Scsgr * SUCH DAMAGE.
322345Scsgr */
332345Scsgr
3495619Smarkm#include <sys/cdefs.h>
352345Scsgr
3695619Smarkm__FBSDID("$FreeBSD$");
3795619Smarkm
382345Scsgr#include <sys/types.h>
392345Scsgr#include <sys/socket.h>
4095619Smarkm
4178455Smikeh#include <rpc/rpc.h>
4278455Smikeh#include <rpc/pmap_clnt.h>
4378455Smikeh#include <rpcsvc/rnusers.h>
4495619Smarkm
4578455Smikeh#include <arpa/inet.h>
4695619Smarkm
4727976Scharnier#include <err.h>
482345Scsgr#include <netdb.h>
492345Scsgr#include <stdio.h>
5027976Scharnier#include <stdlib.h>
5195619Smarkm#include <string.h>
52129459Sdwmalone#include <timeconv.h>
5327976Scharnier#include <unistd.h>
542345Scsgr
5578455Smikeh#define MAX_INT		0x7fffffff
5678455Smikeh#define HOST_WIDTH	20
5778455Smikeh#define LINE_WIDTH	15
582345Scsgr
59227179Sedstatic int longopt;
60227179Sedstatic int allopt;
612345Scsgr
62227179Sedstatic struct host_list {
6378455Smikeh	struct	host_list *next;
6478455Smikeh	struct	in_addr addr;
652345Scsgr} *hosts;
662345Scsgr
6795619Smarkmstatic int
6827976Scharniersearch_host(struct in_addr addr)
692345Scsgr{
702345Scsgr	struct host_list *hp;
718874Srgrimes
7278455Smikeh	if (hosts == NULL)
7378455Smikeh		return (0);
742345Scsgr
752345Scsgr	for (hp = hosts; hp != NULL; hp = hp->next) {
762345Scsgr		if (hp->addr.s_addr == addr.s_addr)
7778455Smikeh			return (1);
782345Scsgr	}
7978455Smikeh	return (0);
802345Scsgr}
812345Scsgr
8295619Smarkmstatic void
8327976Scharnierremember_host(struct in_addr addr)
842345Scsgr{
852345Scsgr	struct host_list *hp;
862345Scsgr
8778455Smikeh	if ((hp = (struct host_list *)malloc(sizeof(struct host_list))) == NULL)
8827976Scharnier		errx(1, "no memory");
892345Scsgr	hp->addr.s_addr = addr.s_addr;
902345Scsgr	hp->next = hosts;
912345Scsgr	hosts = hp;
922345Scsgr}
932345Scsgr
9495619Smarkmstatic int
9574462Salfredrusers_reply(caddr_t replyp, struct sockaddr_in *raddrp)
962345Scsgr{
9795619Smarkm	u_int x;
9895619Smarkm	int idle;
9978455Smikeh	char date[32], idle_time[64], remote[64];
10078455Smikeh	struct hostent *hp;
101129459Sdwmalone	utmpidlearr *up, u;
10278455Smikeh	char *host;
10378455Smikeh	int days, hours, minutes, seconds;
1048874Srgrimes
105129459Sdwmalone	up = &u;
106129459Sdwmalone	memcpy(up, replyp, sizeof(*up));
1072345Scsgr	if (search_host(raddrp->sin_addr))
10878455Smikeh		return (0);
1092345Scsgr
11078455Smikeh	if (!allopt && up->utmpidlearr_len == 0)
11178455Smikeh		return (0);
1128874Srgrimes
11378455Smikeh	hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr,
11478455Smikeh	    sizeof(struct in_addr), AF_INET);
11578455Smikeh	if (hp != NULL)
11678455Smikeh		host = hp->h_name;
11778455Smikeh	else
11878455Smikeh		host = inet_ntoa(raddrp->sin_addr);
1198874Srgrimes
12078455Smikeh	if (!longopt)
12178455Smikeh		printf("%-*s ", HOST_WIDTH, host);
1228874Srgrimes
12378455Smikeh	for (x = 0; x < up->utmpidlearr_len; x++) {
12489572Sdillon		time_t t = _int_to_time(up->utmpidlearr_val[x].ui_utmp.ut_time);
12585638Sdillon		strncpy(date, &(ctime(&t)[4]), sizeof(date) - 1);
1262345Scsgr
12778455Smikeh		idle = up->utmpidlearr_val[x].ui_idle;
12878455Smikeh		sprintf(idle_time, "  :%02d", idle);
12978455Smikeh		if (idle == MAX_INT)
13078455Smikeh			strcpy(idle_time, "??");
13178455Smikeh		else if (idle == 0)
13278455Smikeh			strcpy(idle_time, "");
13378455Smikeh		else {
13478455Smikeh			seconds = idle;
13578455Smikeh			days = seconds / (60 * 60 * 24);
13678455Smikeh			seconds %= (60 * 60 * 24);
13778455Smikeh			hours = seconds / (60 * 60);
13878455Smikeh			seconds %= (60 * 60);
13978455Smikeh			minutes = seconds / 60;
14078455Smikeh			seconds %= 60;
14178455Smikeh			if (idle > 60)
14278455Smikeh				sprintf(idle_time, "%d:%02d", minutes, seconds);
14378455Smikeh			if (idle >= (60 * 60))
14478455Smikeh				sprintf(idle_time, "%d:%02d:%02d",
14578455Smikeh				    hours, minutes, seconds);
14678455Smikeh			if (idle >= (24 * 60 * 60))
14778455Smikeh				sprintf(idle_time, "%d days, %d:%02d:%02d",
14878455Smikeh				    days, hours, minutes, seconds);
14978455Smikeh		}
1502345Scsgr
15178455Smikeh		strncpy(remote, up->utmpidlearr_val[x].ui_utmp.ut_host,
15278455Smikeh		    sizeof(remote) - 1);
15378455Smikeh		if (strlen(remote) != 0)
15478455Smikeh			sprintf(remote, "(%.16s)",
15578455Smikeh			    up->utmpidlearr_val[x].ui_utmp.ut_host);
1562345Scsgr
15778455Smikeh		if (longopt)
15878455Smikeh			printf("%-8.8s %*s:%-*.*s %-12.12s  %6s %.18s\n",
15978455Smikeh			    up->utmpidlearr_val[x].ui_utmp.ut_name,
16078455Smikeh			    HOST_WIDTH, host, LINE_WIDTH, LINE_WIDTH,
16178455Smikeh			    up->utmpidlearr_val[x].ui_utmp.ut_line, date,
16278455Smikeh			    idle_time, remote );
16378455Smikeh		else
16478455Smikeh			printf("%s ",
16578455Smikeh			    up->utmpidlearr_val[x].ui_utmp.ut_name);
16678455Smikeh	}
16778455Smikeh	if (!longopt)
16878455Smikeh		putchar('\n');
1698874Srgrimes
1702345Scsgr	remember_host(raddrp->sin_addr);
17178455Smikeh	return (0);
1722345Scsgr}
1732345Scsgr
17495619Smarkmstatic void
1752345Scsgronehost(char *host)
1762345Scsgr{
17778455Smikeh	utmpidlearr up;
17878455Smikeh	CLIENT *rusers_clnt;
17978455Smikeh	struct sockaddr_in addr;
18078455Smikeh	struct hostent *hp;
18178455Smikeh	struct timeval tv;
1828874Srgrimes
18378455Smikeh	hp = gethostbyname(host);
18478455Smikeh	if (hp == NULL)
18578455Smikeh		errx(1, "unknown host \"%s\"", host);
1862345Scsgr
18778455Smikeh	rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_IDLE, "udp");
18878455Smikeh	if (rusers_clnt == NULL)
18978455Smikeh		errx(1, "%s", clnt_spcreateerror(""));
1902345Scsgr
1912345Scsgr	bzero((char *)&up, sizeof(up));
19278455Smikeh	tv.tv_sec = 15;	/* XXX ?? */
19321094Speter	tv.tv_usec = 0;
194121545Speter	if (clnt_call(rusers_clnt, RUSERSPROC_NAMES, (xdrproc_t)xdr_void, NULL,
195121545Speter	    (xdrproc_t)xdr_utmpidlearr, &up, tv) != RPC_SUCCESS)
19678455Smikeh		errx(1, "%s", clnt_sperror(rusers_clnt, ""));
197129459Sdwmalone	memcpy(&addr.sin_addr.s_addr, hp->h_addr, sizeof(addr.sin_addr.s_addr));
19878455Smikeh	rusers_reply((caddr_t)&up, &addr);
19978456Smikeh	clnt_destroy(rusers_clnt);
2002345Scsgr}
2012345Scsgr
20295619Smarkmstatic void
20395619Smarkmallhosts(void)
2042345Scsgr{
20527976Scharnier	utmpidlearr up;
2062345Scsgr	enum clnt_stat clnt_stat;
2072345Scsgr
2082345Scsgr	bzero((char *)&up, sizeof(up));
20978455Smikeh	clnt_stat = clnt_broadcast(RUSERSPROG, RUSERSVERS_IDLE,
210121545Speter	    RUSERSPROC_NAMES, (xdrproc_t)xdr_void, NULL,
211121545Speter	    (xdrproc_t)xdr_utmpidlearr, (char *)&up,
212121545Speter	    (resultproc_t)rusers_reply);
21327976Scharnier	if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT)
21427976Scharnier		errx(1, "%s", clnt_sperrno(clnt_stat));
2152345Scsgr}
2162345Scsgr
21727976Scharnierstatic void
21895619Smarkmusage(void)
2192345Scsgr{
22078455Smikeh
221146466Sru	fprintf(stderr, "usage: rusers [-al] [host ...]\n");
22278455Smikeh	exit(1);
2232345Scsgr}
2242345Scsgr
22527976Scharnierint
2262345Scsgrmain(int argc, char *argv[])
2272345Scsgr{
22878455Smikeh	int ch;
2298874Srgrimes
23078455Smikeh	while ((ch = getopt(argc, argv, "al")) != -1)
23178455Smikeh		switch (ch) {
23278455Smikeh		case 'a':
23378455Smikeh			allopt++;
23478455Smikeh			break;
23578455Smikeh		case 'l':
23678455Smikeh			longopt++;
23778455Smikeh			break;
23878455Smikeh		default:
23978455Smikeh			usage();
24078455Smikeh			/* NOTREACHED */
24178455Smikeh		}
2422345Scsgr
24378455Smikeh	setlinebuf(stdout);
2442345Scsgr	if (argc == optind)
2452345Scsgr		allhosts();
2462345Scsgr	else {
2472345Scsgr		for (; optind < argc; optind++)
24878455Smikeh			(void)onehost(argv[optind]);
2492345Scsgr	}
25078455Smikeh	exit(0);
2512345Scsgr}
252