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/capsicum.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 cap_rights_t rights; 97 int f, n, i; 98 int d_first; 99 int dfd; 100 time_t ct; 101 102 w = &wd; 103 (void) setlocale(LC_TIME, ""); 104 d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 105 106 while ((ch = getopt(argc, argv, "a")) != -1) { 107 switch ((char)ch) { 108 case 'a': 109 aflg = 1; 110 break; 111 case '?': 112 default: 113 usage(); 114 } 115 } 116 argc -= optind; 117 argv += optind; 118 119 if (argc != 0) 120 usage(); 121 122 if (chdir(_PATH_RWHODIR) < 0) 123 err(1, "chdir(%s)", _PATH_RWHODIR); 124 if ((dirp = opendir(".")) == NULL) 125 err(1, "opendir(%s)", _PATH_RWHODIR); 126 dfd = dirfd(dirp); 127 mp = myutmp; 128 cap_rights_init(&rights, CAP_READ, CAP_LOOKUP); 129 if (cap_rights_limit(dfd, &rights) < 0 && errno != ENOSYS) 130 err(1, "cap_rights_limit failed: %s", _PATH_RWHODIR); 131 /* 132 * Cache files required for time(3) and localtime(3) before entering 133 * capability mode. 134 */ 135 (void) time(&ct); 136 (void) localtime(&ct); 137 if (cap_enter() < 0 && errno != ENOSYS) 138 err(1, "cap_enter"); 139 (void) time(&now); 140 cap_rights_init(&rights, CAP_READ); 141 while ((dp = readdir(dirp)) != NULL) { 142 if (dp->d_ino == 0 || strncmp(dp->d_name, "whod.", 5) != 0) 143 continue; 144 f = openat(dfd, dp->d_name, O_RDONLY); 145 if (f < 0) 146 continue; 147 if (cap_rights_limit(f, &rights) < 0 && errno != ENOSYS) 148 err(1, "cap_rights_limit failed: %s", dp->d_name); 149 cc = read(f, (char *)&wd, sizeof(struct whod)); 150 if (cc < WHDRSIZE) { 151 (void) close(f); 152 continue; 153 } 154 if (down(w, now) != 0) { 155 (void) close(f); 156 continue; 157 } 158 cc -= WHDRSIZE; 159 we = w->wd_we; 160 for (n = cc / sizeof(struct whoent); n > 0; n--) { 161 if (aflg == 0 && we->we_idle >= 60 * 60) { 162 we++; 163 continue; 164 } 165 if (nusers >= NUSERS) 166 errx(1, "too many users"); 167 mp->myutmp = we->we_utmp; 168 mp->myidle = we->we_idle; 169 (void) strcpy(mp->myhost, w->wd_hostname); 170 nusers++; 171 we++; 172 mp++; 173 } 174 (void) close(f); 175 } 176 qsort((char *)myutmp, nusers, sizeof(struct myutmp), utmpcmp); 177 mp = myutmp; 178 width = 0; 179 for (i = 0; i < nusers; i++) { 180 /* append one for the blank and use 8 for the out_line */ 181 int j; 182 183 j = strlen(mp->myhost) + 1 + sizeof(mp->myutmp.out_line); 184 if (j > width) 185 width = j; 186 mp++; 187 } 188 mp = myutmp; 189 for (i = 0; i < nusers; i++) { 190 char buf[BUFSIZ], cbuf[80]; 191 time_t t; 192 193 t = _int_to_time(mp->myutmp.out_time); 194 strftime(cbuf, sizeof(cbuf), d_first ? "%e %b %R" : "%b %e %R", 195 localtime(&t)); 196 (void) sprintf(buf, "%s:%-.*s", mp->myhost, 197 (int)sizeof(mp->myutmp.out_line), mp->myutmp.out_line); 198 printf("%-*.*s %-*s %s", 199 (int)sizeof(mp->myutmp.out_name), 200 (int)sizeof(mp->myutmp.out_name), 201 mp->myutmp.out_name, width, buf, cbuf); 202 mp->myidle /= 60; 203 if (mp->myidle != 0) { 204 if (aflg != 0) { 205 if (mp->myidle >= 100 * 60) 206 mp->myidle = 100 * 60 - 1; 207 if (mp->myidle >= 60) 208 printf(" %2d", mp->myidle / 60); 209 else 210 printf(" "); 211 } else { 212 printf(" "); 213 } 214 printf(":%02d", mp->myidle % 60); 215 } 216 printf("\n"); 217 mp++; 218 } 219 exit(0); 220 } 221 222 223 static void 224 usage(void) 225 { 226 227 fprintf(stderr, "usage: rwho [-a]\n"); 228 exit(1); 229 } 230 231 #define MYUTMP(a) ((const struct myutmp *)(a)) 232 233 static int 234 utmpcmp(const void *u1, const void *u2) 235 { 236 int rc; 237 238 rc = strncmp(MYUTMP(u1)->myutmp.out_name, MYUTMP(u2)->myutmp.out_name, 239 sizeof(MYUTMP(u2)->myutmp.out_name)); 240 if (rc != 0) 241 return (rc); 242 rc = strcmp(MYUTMP(u1)->myhost, MYUTMP(u2)->myhost); 243 if (rc != 0) 244 return (rc); 245 return (strncmp(MYUTMP(u1)->myutmp.out_line, 246 MYUTMP(u2)->myutmp.out_line, sizeof(MYUTMP(u2)->myutmp.out_line))); 247 } 248