1/* $NetBSD: rwho.c,v 1.18 2008/07/21 14:19:25 lukem Exp $ */ 2 3/* 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33#ifndef lint 34__COPYRIGHT("@(#) Copyright (c) 1983, 1993\ 35 The Regents of the University of California. All rights reserved."); 36#endif /* not lint */ 37 38#ifndef lint 39/*static char sccsid[] = "from: @(#)rwho.c 8.1 (Berkeley) 6/6/93";*/ 40__RCSID("$NetBSD: rwho.c,v 1.18 2008/07/21 14:19:25 lukem Exp $"); 41#endif /* not lint */ 42 43#include <sys/param.h> 44#include <sys/file.h> 45 46#include <protocols/rwhod.h> 47 48#include <dirent.h> 49#include <err.h> 50#include <locale.h> 51#include <stdio.h> 52#include <stdlib.h> 53#include <string.h> 54#include <time.h> 55#include <fcntl.h> 56#include <unistd.h> 57#include <utmp.h> 58#include <sysexits.h> 59 60static void usage(void) __dead; 61static int utmpcmp(const void *, const void *); 62 63/* 64 * this macro should be shared with ruptime. 65 */ 66#define DOWN(w,now) ((now) - (w).wd_recvtime > 11 * 60) 67#define WHDRSIZE (sizeof(struct whod) - \ 68 sizeof (((struct whod *)NULL)->wd_we)) 69 70struct my_utmp { 71 char myhost[MAXHOSTNAMELEN]; 72 int myidle; 73 struct outmp myutmp; 74}; 75 76int 77main(int argc, char **argv) 78{ 79 DIR *dirp; 80 struct dirent *dp; 81 struct whoent *we; 82 struct whod wd; 83 struct my_utmp *mp, *start; 84 time_t now; 85 int ch; 86 size_t width, n, i, nhosts, nusers, namount; 87 int aflg, qflg, hflg; 88 89 setprogname(argv[0]); 90 (void)setlocale(LC_TIME, ""); 91 aflg = nusers = nhosts = qflg = hflg = 0; 92 namount = 40; 93 start = NULL; 94 now = 0; 95 96 while ((ch = getopt(argc, argv, "aHq")) != -1) 97 switch(ch) { 98 case 'a': 99 aflg = 1; 100 break; 101 case 'q': 102 qflg = 1; 103 break; 104 case 'H': 105 hflg = 1; 106 break; 107 default: 108 usage(); 109 } 110 111 if(optind != argc) 112 usage(); 113 114 if (qflg) { 115 aflg = 0; 116 hflg = 0; 117 } 118 119 if (chdir(_PATH_RWHODIR) || (dirp = opendir(".")) == NULL) 120 err(EXIT_FAILURE, "Cannot access `%s'", _PATH_RWHODIR); 121 122 (void)time(&now); 123 124 if ((start = malloc(sizeof(*start) * namount)) == NULL) 125 err(EXIT_FAILURE, "malloc"); 126 127 while ((dp = readdir(dirp)) != NULL) { 128 int f; 129 ssize_t cc; 130 131 if (dp->d_ino == 0 || strncmp(dp->d_name, "whod.", 5)) 132 continue; 133 134 f = open(dp->d_name, O_RDONLY); 135 if (f < 0) 136 continue; 137 cc = read(f, &wd, sizeof (wd)); 138 if (cc < (ssize_t)WHDRSIZE) { 139 (void)close(f); 140 continue; 141 } 142 nhosts++; 143 if (DOWN(wd, now)) { 144 (void)close(f); 145 continue; 146 } 147 cc -= WHDRSIZE; 148 we = wd.wd_we; 149 for (n = cc / sizeof (struct whoent); n > 0; n--) { 150 if (aflg == 0 && we->we_idle >= 60*60) { 151 we++; 152 continue; 153 } 154 155 if (nusers == namount) { 156 namount = namount + 40; 157 if ((start = realloc(start, 158 sizeof(struct my_utmp) * namount)) == NULL) 159 err(1, "realloc"); 160 } 161 162 mp = start + nusers; 163 164 mp->myutmp = we->we_utmp; 165 mp->myidle = we->we_idle; 166 (void)strcpy(mp->myhost, wd.wd_hostname); 167 nusers++; we++; mp++; 168 } 169 (void)close(f); 170 } 171 172 if (nhosts == 0) 173 errx(EX_OK, "No hosts in `%s'.", _PATH_RWHODIR); 174 175 mp = start; 176 qsort(start, nusers, sizeof(*start), utmpcmp); 177 width = 0; 178 for (i = 0; i < nusers; i++) { 179 size_t j = strlen(mp->myhost) + 1 + strlen(mp->myutmp.out_line); 180 if (j > width) 181 width = j; 182 mp++; 183 } 184 mp = start; 185 if (hflg) { 186 (void)printf("%-*.*s %-*s %-12s %-*s\n", UT_NAMESIZE, 187 UT_NAMESIZE, "USER", (int)width, "LINE", "WHEN", 188 (int)width, "IDLE"); 189 } 190 for (i = 0; i < nusers; i++) { 191 char buf[BUFSIZ], cbuf[80]; 192 time_t t; 193 194 if (qflg) { 195 (void)printf("%-*.*s\n", UT_NAMESIZE, UT_NAMESIZE, 196 mp->myutmp.out_name); 197 mp++; 198 continue; 199 } 200 t = mp->myutmp.out_time; 201 (void)strftime(cbuf, sizeof(cbuf), "%c", localtime(&t)); 202 (void)snprintf(buf, sizeof(buf), "%s:%s", mp->myhost, 203 mp->myutmp.out_line); 204 (void)printf("%-*.*s %-*s %.12s", UT_NAMESIZE, UT_NAMESIZE, 205 mp->myutmp.out_name, (int)width, buf, cbuf + 4); 206 mp->myidle /= 60; 207 if (mp->myidle) { 208 if (aflg) { 209 if (mp->myidle >= 100 * 60) 210 mp->myidle = 100 * 60 - 1; 211 if (mp->myidle >= 60) 212 (void)printf(" %2d", mp->myidle / 60); 213 else 214 (void)printf(" "); 215 } else 216 (void)printf(" "); 217 (void)printf(":%02d", mp->myidle % 60); 218 } 219 (void)printf("\n"); 220 mp++; 221 } 222 223 if (qflg) 224 (void)printf("# users = %zd\n", nusers); 225 226 return EX_OK; 227} 228 229static int 230utmpcmp(const void *v1, const void *v2) 231{ 232 const struct my_utmp *u1, *u2; 233 int rc; 234 235 u1 = v1; 236 u2 = v2; 237 rc = strncmp(u1->myutmp.out_name, u2->myutmp.out_name, 8); 238 if (rc) 239 return rc; 240 rc = strcmp(u1->myhost, u2->myhost); 241 if (rc) 242 return rc; 243 return strncmp(u1->myutmp.out_line, u2->myutmp.out_line, 8); 244} 245 246static void 247usage(void) 248{ 249 (void)fprintf(stderr, "Usage: %s [-aHq]\n", getprogname()); 250 exit(1); 251} 252