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