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