xref: /freebsd/usr.bin/rwho/rwho.c (revision 0b8224d1cc9dc6c9778ba04a75b2c8d47e5d7481)
1c05bfdd3SPawel Jakub Dawidek /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
4c05bfdd3SPawel Jakub Dawidek  * Copyright (c) 1983, 1993 The Regents of the University of California.
57c33a30aSPawel Jakub Dawidek  * Copyright (c) 2013 Mariusz Zaborski <oshogbo@FreeBSD.org>
6c05bfdd3SPawel Jakub Dawidek  * All rights reserved.
79b50d902SRodney W. Grimes  *
89b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
99b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
109b50d902SRodney W. Grimes  * are met:
119b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
129b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
139b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
149b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
159b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
16fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
179b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
189b50d902SRodney W. Grimes  *    without specific prior written permission.
199b50d902SRodney W. Grimes  *
209b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
219b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
229b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
239b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
249b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
259b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
269b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
279b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
289b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
299b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
309b50d902SRodney W. Grimes  * SUCH DAMAGE.
319b50d902SRodney W. Grimes  */
329b50d902SRodney W. Grimes 
33b881b8beSRobert Watson #include <sys/capsicum.h>
349b50d902SRodney W. Grimes #include <sys/param.h>
359b50d902SRodney W. Grimes #include <sys/file.h>
36301777f2SMark Murray 
379b50d902SRodney W. Grimes #include <protocols/rwhod.h>
38301777f2SMark Murray 
397672a014SMariusz Zaborski #include <capsicum_helpers.h>
400c8ea4d4SBruce Evans #include <dirent.h>
41157f1c6cSPhilippe Charnier #include <err.h>
427c33a30aSPawel Jakub Dawidek #include <errno.h>
433bd65123SAndrey A. Chernov #include <langinfo.h>
44f6d3b9acSAndrey A. Chernov #include <locale.h>
450f456e3cSAndrey A. Chernov #include <stdio.h>
46157f1c6cSPhilippe Charnier #include <stdlib.h>
470f456e3cSAndrey A. Chernov #include <string.h>
480f456e3cSAndrey A. Chernov #include <time.h>
49301777f2SMark Murray #include <timeconv.h>
50157f1c6cSPhilippe Charnier #include <unistd.h>
519b50d902SRodney W. Grimes 
529b50d902SRodney W. Grimes #define	NUSERS		1000
53301777f2SMark Murray #define	WHDRSIZE	(ssize_t)(sizeof(wd) - sizeof(wd.wd_we))
549b50d902SRodney W. Grimes /*
559b50d902SRodney W. Grimes  * this macro should be shared with ruptime.
569b50d902SRodney W. Grimes  */
579b50d902SRodney W. Grimes #define	down(w,now)	((now) - (w)->wd_recvtime > 11 * 60)
589b50d902SRodney W. Grimes 
59c05bfdd3SPawel Jakub Dawidek static DIR	*dirp;
60c05bfdd3SPawel Jakub Dawidek static struct	whod wd;
61c05bfdd3SPawel Jakub Dawidek static int	nusers;
62c05bfdd3SPawel Jakub Dawidek static struct	myutmp {
63c05bfdd3SPawel Jakub Dawidek 	char    myhost[sizeof(wd.wd_hostname)];
64c05bfdd3SPawel Jakub Dawidek 	int	myidle;
65c05bfdd3SPawel Jakub Dawidek 	struct	outmp myutmp;
66c05bfdd3SPawel Jakub Dawidek } myutmp[NUSERS];
67c05bfdd3SPawel Jakub Dawidek 
68af397f37SEd Schouten static time_t	now;
69af397f37SEd Schouten static int	aflg;
709b50d902SRodney W. Grimes 
71*1a7ac2bdSAlfonso Gregory static void usage(void) __dead2;
72af397f37SEd Schouten static int utmpcmp(const void *, const void *);
73157f1c6cSPhilippe Charnier 
74157f1c6cSPhilippe Charnier int
main(int argc,char * argv[])75301777f2SMark Murray main(int argc, char *argv[])
769b50d902SRodney W. Grimes {
779b50d902SRodney W. Grimes 	int ch;
780c8ea4d4SBruce Evans 	struct dirent *dp;
79301777f2SMark Murray 	int width;
80301777f2SMark Murray 	ssize_t cc;
81c05bfdd3SPawel Jakub Dawidek 	struct whod *w;
82c05bfdd3SPawel Jakub Dawidek 	struct whoent *we;
83c05bfdd3SPawel Jakub Dawidek 	struct myutmp *mp;
847008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
859b50d902SRodney W. Grimes 	int f, n, i;
863bd65123SAndrey A. Chernov 	int d_first;
877c33a30aSPawel Jakub Dawidek 	int dfd;
887c33a30aSPawel Jakub Dawidek 	time_t ct;
899b50d902SRodney W. Grimes 
90c05bfdd3SPawel Jakub Dawidek 	w = &wd;
91f6d3b9acSAndrey A. Chernov 	(void) setlocale(LC_TIME, "");
923bd65123SAndrey A. Chernov 	d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
93f6d3b9acSAndrey A. Chernov 
94c05bfdd3SPawel Jakub Dawidek 	while ((ch = getopt(argc, argv, "a")) != -1) {
959b50d902SRodney W. Grimes 		switch ((char)ch) {
969b50d902SRodney W. Grimes 		case 'a':
979b50d902SRodney W. Grimes 			aflg = 1;
989b50d902SRodney W. Grimes 			break;
999b50d902SRodney W. Grimes 		case '?':
1009b50d902SRodney W. Grimes 		default:
101157f1c6cSPhilippe Charnier 			usage();
1029b50d902SRodney W. Grimes 		}
103c05bfdd3SPawel Jakub Dawidek 	}
104e1f4275aSSteve Price 	argc -= optind;
105e1f4275aSSteve Price 	argv += optind;
106e1f4275aSSteve Price 
107e1f4275aSSteve Price 	if (argc != 0)
108e1f4275aSSteve Price 		usage();
109e1f4275aSSteve Price 
1107c33a30aSPawel Jakub Dawidek 	if (chdir(_PATH_RWHODIR) < 0)
1117c33a30aSPawel Jakub Dawidek 		err(1, "chdir(%s)", _PATH_RWHODIR);
1127c33a30aSPawel Jakub Dawidek 	if ((dirp = opendir(".")) == NULL)
1137c33a30aSPawel Jakub Dawidek 		err(1, "opendir(%s)", _PATH_RWHODIR);
1147c33a30aSPawel Jakub Dawidek 	dfd = dirfd(dirp);
1159b50d902SRodney W. Grimes 	mp = myutmp;
1167008be5bSPawel Jakub Dawidek 	cap_rights_init(&rights, CAP_READ, CAP_LOOKUP);
117377421dfSMariusz Zaborski 	if (caph_rights_limit(dfd, &rights) < 0)
1187c33a30aSPawel Jakub Dawidek 		err(1, "cap_rights_limit failed: %s", _PATH_RWHODIR);
1197c33a30aSPawel Jakub Dawidek 	/*
1207c33a30aSPawel Jakub Dawidek 	 * Cache files required for time(3) and localtime(3) before entering
1217c33a30aSPawel Jakub Dawidek 	 * capability mode.
1227c33a30aSPawel Jakub Dawidek 	 */
1237c33a30aSPawel Jakub Dawidek 	(void) time(&ct);
1247c33a30aSPawel Jakub Dawidek 	(void) localtime(&ct);
1257672a014SMariusz Zaborski 	if (caph_enter() < 0)
1267c33a30aSPawel Jakub Dawidek 		err(1, "cap_enter");
1279b50d902SRodney W. Grimes 	(void) time(&now);
1287008be5bSPawel Jakub Dawidek 	cap_rights_init(&rights, CAP_READ);
129c05bfdd3SPawel Jakub Dawidek 	while ((dp = readdir(dirp)) != NULL) {
130c05bfdd3SPawel Jakub Dawidek 		if (dp->d_ino == 0 || strncmp(dp->d_name, "whod.", 5) != 0)
1319b50d902SRodney W. Grimes 			continue;
1327c33a30aSPawel Jakub Dawidek 		f = openat(dfd, dp->d_name, O_RDONLY);
1339b50d902SRodney W. Grimes 		if (f < 0)
1349b50d902SRodney W. Grimes 			continue;
135377421dfSMariusz Zaborski 		if (caph_rights_limit(f, &rights) < 0)
1367c33a30aSPawel Jakub Dawidek 			err(1, "cap_rights_limit failed: %s", dp->d_name);
1379b50d902SRodney W. Grimes 		cc = read(f, (char *)&wd, sizeof(struct whod));
1389b50d902SRodney W. Grimes 		if (cc < WHDRSIZE) {
1399b50d902SRodney W. Grimes 			(void) close(f);
1409b50d902SRodney W. Grimes 			continue;
1419b50d902SRodney W. Grimes 		}
142c05bfdd3SPawel Jakub Dawidek 		if (down(w, now) != 0) {
1439b50d902SRodney W. Grimes 			(void) close(f);
1449b50d902SRodney W. Grimes 			continue;
1459b50d902SRodney W. Grimes 		}
1469b50d902SRodney W. Grimes 		cc -= WHDRSIZE;
1479b50d902SRodney W. Grimes 		we = w->wd_we;
1489b50d902SRodney W. Grimes 		for (n = cc / sizeof(struct whoent); n > 0; n--) {
1499b50d902SRodney W. Grimes 			if (aflg == 0 && we->we_idle >= 60 * 60) {
1509b50d902SRodney W. Grimes 				we++;
1519b50d902SRodney W. Grimes 				continue;
1529b50d902SRodney W. Grimes 			}
153157f1c6cSPhilippe Charnier 			if (nusers >= NUSERS)
154157f1c6cSPhilippe Charnier 				errx(1, "too many users");
155c05bfdd3SPawel Jakub Dawidek 			mp->myutmp = we->we_utmp;
156c05bfdd3SPawel Jakub Dawidek 			mp->myidle = we->we_idle;
1579b50d902SRodney W. Grimes 			(void) strcpy(mp->myhost, w->wd_hostname);
158c05bfdd3SPawel Jakub Dawidek 			nusers++;
159c05bfdd3SPawel Jakub Dawidek 			we++;
160c05bfdd3SPawel Jakub Dawidek 			mp++;
1619b50d902SRodney W. Grimes 		}
1629b50d902SRodney W. Grimes 		(void) close(f);
1639b50d902SRodney W. Grimes 	}
1649b50d902SRodney W. Grimes 	qsort((char *)myutmp, nusers, sizeof(struct myutmp), utmpcmp);
1659b50d902SRodney W. Grimes 	mp = myutmp;
1669b50d902SRodney W. Grimes 	width = 0;
1679b50d902SRodney W. Grimes 	for (i = 0; i < nusers; i++) {
16804dc4fc2SAndreas Schulz 		/* append one for the blank and use 8 for the out_line */
169c05bfdd3SPawel Jakub Dawidek 		int j;
170c05bfdd3SPawel Jakub Dawidek 
171c05bfdd3SPawel Jakub Dawidek 		j = strlen(mp->myhost) + 1 + sizeof(mp->myutmp.out_line);
1729b50d902SRodney W. Grimes 		if (j > width)
1739b50d902SRodney W. Grimes 			width = j;
1749b50d902SRodney W. Grimes 		mp++;
1759b50d902SRodney W. Grimes 	}
1769b50d902SRodney W. Grimes 	mp = myutmp;
1779b50d902SRodney W. Grimes 	for (i = 0; i < nusers; i++) {
1788327624eSAndrey A. Chernov 		char buf[BUFSIZ], cbuf[80];
179c05bfdd3SPawel Jakub Dawidek 		time_t t;
1803bd65123SAndrey A. Chernov 
181c05bfdd3SPawel Jakub Dawidek 		t = _int_to_time(mp->myutmp.out_time);
182d7499324SPawel Jakub Dawidek 		strftime(cbuf, sizeof(cbuf), d_first ? "%e %b %R" : "%b %e %R",
18346ca39e2SMatthew Dillon 		    localtime(&t));
1847618cd12SAndrey A. Chernov 		(void) sprintf(buf, "%s:%-.*s", mp->myhost,
185c75216d2SEd Schouten 		    (int)sizeof(mp->myutmp.out_line), mp->myutmp.out_line);
1863bd65123SAndrey A. Chernov 		printf("%-*.*s %-*s %s",
187c75216d2SEd Schouten 		    (int)sizeof(mp->myutmp.out_name),
188c75216d2SEd Schouten 		    (int)sizeof(mp->myutmp.out_name),
189d7499324SPawel Jakub Dawidek 		    mp->myutmp.out_name, width, buf, cbuf);
1909b50d902SRodney W. Grimes 		mp->myidle /= 60;
191c05bfdd3SPawel Jakub Dawidek 		if (mp->myidle != 0) {
192c05bfdd3SPawel Jakub Dawidek 			if (aflg != 0) {
1939b50d902SRodney W. Grimes 				if (mp->myidle >= 100 * 60)
1949b50d902SRodney W. Grimes 					mp->myidle = 100 * 60 - 1;
1959b50d902SRodney W. Grimes 				if (mp->myidle >= 60)
1969b50d902SRodney W. Grimes 					printf(" %2d", mp->myidle / 60);
1979b50d902SRodney W. Grimes 				else
1989b50d902SRodney W. Grimes 					printf("   ");
199c05bfdd3SPawel Jakub Dawidek 			} else {
2009b50d902SRodney W. Grimes 				printf(" ");
201c05bfdd3SPawel Jakub Dawidek 			}
2029b50d902SRodney W. Grimes 			printf(":%02d", mp->myidle % 60);
2039b50d902SRodney W. Grimes 		}
2049b50d902SRodney W. Grimes 		printf("\n");
2059b50d902SRodney W. Grimes 		mp++;
2069b50d902SRodney W. Grimes 	}
2079b50d902SRodney W. Grimes 	exit(0);
2089b50d902SRodney W. Grimes }
2099b50d902SRodney W. Grimes 
210157f1c6cSPhilippe Charnier 
211157f1c6cSPhilippe Charnier static void
usage(void)212301777f2SMark Murray usage(void)
213157f1c6cSPhilippe Charnier {
214d7499324SPawel Jakub Dawidek 
215157f1c6cSPhilippe Charnier 	fprintf(stderr, "usage: rwho [-a]\n");
216157f1c6cSPhilippe Charnier 	exit(1);
217157f1c6cSPhilippe Charnier }
218157f1c6cSPhilippe Charnier 
219301777f2SMark Murray #define MYUTMP(a) ((const struct myutmp *)(a))
220e1f4275aSSteve Price 
221af397f37SEd Schouten static int
utmpcmp(const void * u1,const void * u2)222301777f2SMark Murray utmpcmp(const void *u1, const void *u2)
2239b50d902SRodney W. Grimes {
2249b50d902SRodney W. Grimes 	int rc;
2259b50d902SRodney W. Grimes 
226e1f4275aSSteve Price 	rc = strncmp(MYUTMP(u1)->myutmp.out_name, MYUTMP(u2)->myutmp.out_name,
227e1f4275aSSteve Price 	    sizeof(MYUTMP(u2)->myutmp.out_name));
228c05bfdd3SPawel Jakub Dawidek 	if (rc != 0)
2299b50d902SRodney W. Grimes 		return (rc);
230e1f4275aSSteve Price 	rc = strcmp(MYUTMP(u1)->myhost, MYUTMP(u2)->myhost);
231c05bfdd3SPawel Jakub Dawidek 	if (rc != 0)
2329b50d902SRodney W. Grimes 		return (rc);
233d7499324SPawel Jakub Dawidek 	return (strncmp(MYUTMP(u1)->myutmp.out_line,
234d7499324SPawel Jakub Dawidek 	    MYUTMP(u2)->myutmp.out_line, sizeof(MYUTMP(u2)->myutmp.out_line)));
2359b50d902SRodney W. Grimes }
236