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