1252596Spjd/*- 2252596Spjd * Copyright (c) 1983, 1993 The Regents of the University of California. 3252598Spjd * Copyright (c) 2013 Mariusz Zaborski <oshogbo@FreeBSD.org> 4252596Spjd * All rights reserved. 51590Srgrimes * 61590Srgrimes * Redistribution and use in source and binary forms, with or without 71590Srgrimes * modification, are permitted provided that the following conditions 81590Srgrimes * are met: 91590Srgrimes * 1. Redistributions of source code must retain the above copyright 101590Srgrimes * notice, this list of conditions and the following disclaimer. 111590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121590Srgrimes * notice, this list of conditions and the following disclaimer in the 131590Srgrimes * documentation and/or other materials provided with the distribution. 141590Srgrimes * 4. Neither the name of the University nor the names of its contributors 151590Srgrimes * may be used to endorse or promote products derived from this software 161590Srgrimes * without specific prior written permission. 171590Srgrimes * 181590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 191590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 201590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 211590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 221590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 231590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 241590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 251590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 261590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 271590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 281590Srgrimes * SUCH DAMAGE. 291590Srgrimes */ 301590Srgrimes 311590Srgrimes#ifndef lint 3227978Scharnierstatic const char copyright[] = 331590Srgrimes"@(#) Copyright (c) 1983, 1993\n\ 341590Srgrimes The Regents of the University of California. All rights reserved.\n"; 351590Srgrimes#endif /* not lint */ 361590Srgrimes 371590Srgrimes#ifndef lint 3827978Scharnier#if 0 391590Srgrimesstatic char sccsid[] = "@(#)rwho.c 8.1 (Berkeley) 6/6/93"; 4027978Scharnier#endif 411590Srgrimes#endif /* not lint */ 421590Srgrimes 4399218Smarkm#include <sys/cdefs.h> 4499218Smarkm__FBSDID("$FreeBSD$"); 4599218Smarkm 46280250Srwatson#include <sys/capsicum.h> 471590Srgrimes#include <sys/param.h> 481590Srgrimes#include <sys/file.h> 4999218Smarkm 501590Srgrimes#include <protocols/rwhod.h> 5199218Smarkm 5218485Sbde#include <dirent.h> 5327978Scharnier#include <err.h> 54252598Spjd#include <errno.h> 5574593Sache#include <langinfo.h> 5620156Sache#include <locale.h> 571590Srgrimes#include <stdio.h> 5827978Scharnier#include <stdlib.h> 5920156Sache#include <string.h> 609992Sache#include <time.h> 6199218Smarkm#include <timeconv.h> 6227978Scharnier#include <unistd.h> 631590Srgrimes 64252596Spjd#define NUSERS 1000 65252599Spjd#define WHDRSIZE (ssize_t)(sizeof(wd) - sizeof(wd.wd_we)) 66252596Spjd/* 67252596Spjd * this macro should be shared with ruptime. 68252596Spjd */ 69252596Spjd#define down(w,now) ((now) - (w)->wd_recvtime > 11 * 60) 70252596Spjd 71227181Sedstatic DIR *dirp; 72227181Sedstatic struct whod wd; 73252596Spjdstatic int nusers; 74227181Sedstatic struct myutmp { 7520165Sache char myhost[sizeof(wd.wd_hostname)]; 761590Srgrimes int myidle; 771590Srgrimes struct outmp myutmp; 781590Srgrimes} myutmp[NUSERS]; 791590Srgrimes 80227181Sedstatic time_t now; 81227181Sedstatic int aflg; 821590Srgrimes 8392921Simpstatic void usage(void); 84227181Sedstatic int utmpcmp(const void *, const void *); 8527978Scharnier 8627978Scharnierint 8799218Smarkmmain(int argc, char *argv[]) 881590Srgrimes{ 891590Srgrimes int ch; 9018485Sbde struct dirent *dp; 9199218Smarkm int width; 9299218Smarkm ssize_t cc; 93252596Spjd struct whod *w; 94252596Spjd struct whoent *we; 95252596Spjd struct myutmp *mp; 96255219Spjd cap_rights_t rights; 971590Srgrimes int f, n, i; 9874593Sache int d_first; 99252598Spjd int dfd; 100252598Spjd time_t ct; 1011590Srgrimes 102252596Spjd w = &wd; 10311758Sache (void) setlocale(LC_TIME, ""); 10474593Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 10511758Sache 106252596Spjd while ((ch = getopt(argc, argv, "a")) != -1) { 107252596Spjd switch ((char)ch) { 1081590Srgrimes case 'a': 1091590Srgrimes aflg = 1; 1101590Srgrimes break; 1111590Srgrimes case '?': 1121590Srgrimes default: 11327978Scharnier usage(); 1141590Srgrimes } 115252596Spjd } 11635659Ssteve argc -= optind; 11735659Ssteve argv += optind; 11835659Ssteve 11935659Ssteve if (argc != 0) 12035659Ssteve usage(); 12135659Ssteve 122252598Spjd if (chdir(_PATH_RWHODIR) < 0) 123252598Spjd err(1, "chdir(%s)", _PATH_RWHODIR); 124252598Spjd if ((dirp = opendir(".")) == NULL) 125252598Spjd err(1, "opendir(%s)", _PATH_RWHODIR); 126252598Spjd dfd = dirfd(dirp); 1271590Srgrimes mp = myutmp; 128255219Spjd cap_rights_init(&rights, CAP_READ, CAP_LOOKUP); 129255219Spjd if (cap_rights_limit(dfd, &rights) < 0 && errno != ENOSYS) 130252598Spjd err(1, "cap_rights_limit failed: %s", _PATH_RWHODIR); 131252598Spjd /* 132252598Spjd * Cache files required for time(3) and localtime(3) before entering 133252598Spjd * capability mode. 134252598Spjd */ 135252598Spjd (void) time(&ct); 136252598Spjd (void) localtime(&ct); 137252598Spjd if (cap_enter() < 0 && errno != ENOSYS) 138252598Spjd err(1, "cap_enter"); 139252596Spjd (void) time(&now); 140255219Spjd cap_rights_init(&rights, CAP_READ); 141252596Spjd while ((dp = readdir(dirp)) != NULL) { 142252596Spjd if (dp->d_ino == 0 || strncmp(dp->d_name, "whod.", 5) != 0) 1431590Srgrimes continue; 144252598Spjd f = openat(dfd, dp->d_name, O_RDONLY); 1451590Srgrimes if (f < 0) 1461590Srgrimes continue; 147255219Spjd if (cap_rights_limit(f, &rights) < 0 && errno != ENOSYS) 148252598Spjd err(1, "cap_rights_limit failed: %s", dp->d_name); 149252599Spjd cc = read(f, (char *)&wd, sizeof(struct whod)); 1501590Srgrimes if (cc < WHDRSIZE) { 1511590Srgrimes (void) close(f); 1521590Srgrimes continue; 1531590Srgrimes } 154252599Spjd if (down(w, now) != 0) { 1551590Srgrimes (void) close(f); 1561590Srgrimes continue; 1571590Srgrimes } 1581590Srgrimes cc -= WHDRSIZE; 1591590Srgrimes we = w->wd_we; 160252599Spjd for (n = cc / sizeof(struct whoent); n > 0; n--) { 161252596Spjd if (aflg == 0 && we->we_idle >= 60 * 60) { 1621590Srgrimes we++; 1631590Srgrimes continue; 1641590Srgrimes } 16527978Scharnier if (nusers >= NUSERS) 16627978Scharnier errx(1, "too many users"); 167252596Spjd mp->myutmp = we->we_utmp; 168252596Spjd mp->myidle = we->we_idle; 1691590Srgrimes (void) strcpy(mp->myhost, w->wd_hostname); 170252596Spjd nusers++; 171252596Spjd we++; 172252596Spjd mp++; 1731590Srgrimes } 1741590Srgrimes (void) close(f); 1751590Srgrimes } 176252599Spjd qsort((char *)myutmp, nusers, sizeof(struct myutmp), utmpcmp); 1771590Srgrimes mp = myutmp; 1781590Srgrimes width = 0; 1791590Srgrimes for (i = 0; i < nusers; i++) { 1805239Sats /* append one for the blank and use 8 for the out_line */ 181252596Spjd int j; 182252596Spjd 183252596Spjd j = strlen(mp->myhost) + 1 + sizeof(mp->myutmp.out_line); 1841590Srgrimes if (j > width) 1851590Srgrimes width = j; 1861590Srgrimes mp++; 1871590Srgrimes } 1881590Srgrimes mp = myutmp; 1891590Srgrimes for (i = 0; i < nusers; i++) { 1909992Sache char buf[BUFSIZ], cbuf[80]; 191252596Spjd time_t t; 19274593Sache 193252596Spjd t = _int_to_time(mp->myutmp.out_time); 194252599Spjd strftime(cbuf, sizeof(cbuf), d_first ? "%e %b %R" : "%b %e %R", 195252596Spjd localtime(&t)); 196252596Spjd (void) sprintf(buf, "%s:%-.*s", mp->myhost, 197252596Spjd (int)sizeof(mp->myutmp.out_line), mp->myutmp.out_line); 19874593Sache printf("%-*.*s %-*s %s", 199252596Spjd (int)sizeof(mp->myutmp.out_name), 200252596Spjd (int)sizeof(mp->myutmp.out_name), 201252599Spjd mp->myutmp.out_name, width, buf, cbuf); 2021590Srgrimes mp->myidle /= 60; 203252596Spjd if (mp->myidle != 0) { 204252596Spjd if (aflg != 0) { 205252596Spjd if (mp->myidle >= 100 * 60) 206252596Spjd mp->myidle = 100 * 60 - 1; 2071590Srgrimes if (mp->myidle >= 60) 2081590Srgrimes printf(" %2d", mp->myidle / 60); 2091590Srgrimes else 2101590Srgrimes printf(" "); 211252596Spjd } else { 2121590Srgrimes printf(" "); 213252596Spjd } 2141590Srgrimes printf(":%02d", mp->myidle % 60); 2151590Srgrimes } 2161590Srgrimes printf("\n"); 2171590Srgrimes mp++; 2181590Srgrimes } 2191590Srgrimes exit(0); 2201590Srgrimes} 2211590Srgrimes 22227978Scharnier 22327978Scharnierstatic void 22499218Smarkmusage(void) 22527978Scharnier{ 226252599Spjd 22727978Scharnier fprintf(stderr, "usage: rwho [-a]\n"); 22827978Scharnier exit(1); 22927978Scharnier} 23027978Scharnier 23199218Smarkm#define MYUTMP(a) ((const struct myutmp *)(a)) 23235659Ssteve 233227181Sedstatic int 23499218Smarkmutmpcmp(const void *u1, const void *u2) 2351590Srgrimes{ 2361590Srgrimes int rc; 2371590Srgrimes 23835659Ssteve rc = strncmp(MYUTMP(u1)->myutmp.out_name, MYUTMP(u2)->myutmp.out_name, 239252596Spjd sizeof(MYUTMP(u2)->myutmp.out_name)); 240252596Spjd if (rc != 0) 2411590Srgrimes return (rc); 24235659Ssteve rc = strcmp(MYUTMP(u1)->myhost, MYUTMP(u2)->myhost); 243252596Spjd if (rc != 0) 2441590Srgrimes return (rc); 245252599Spjd return (strncmp(MYUTMP(u1)->myutmp.out_line, 246252599Spjd MYUTMP(u2)->myutmp.out_line, sizeof(MYUTMP(u2)->myutmp.out_line))); 2471590Srgrimes} 248