1 /* $OpenBSD: who.c,v 1.24 2015/10/10 22:06:41 deraadt Exp $ */ 2 /* $NetBSD: who.c,v 1.4 1994/12/07 04:28:49 jtc Exp $ */ 3 4 /* 5 * Copyright (c) 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Michael Fischbein. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <paths.h> 39 #include <pwd.h> 40 #include <utmp.h> 41 #include <stdio.h> 42 #include <string.h> 43 #include <stdlib.h> 44 #include <unistd.h> 45 #include <time.h> 46 #include <err.h> 47 #include <locale.h> 48 49 void output(struct utmp *); 50 void output_labels(void); 51 void who_am_i(FILE *); 52 void usage(void); 53 FILE *file(char *); 54 55 int only_current_term; /* show info about the current terminal only */ 56 int show_term; /* show term state */ 57 int show_idle; /* show idle time */ 58 int show_labels; /* show column labels */ 59 int show_quick; /* quick, names only */ 60 61 #define NAME_WIDTH 8 62 #define HOST_WIDTH 45 63 64 int hostwidth = HOST_WIDTH; 65 char *mytty; 66 67 int 68 main(int argc, char *argv[]) 69 { 70 struct utmp usr; 71 FILE *ufp; 72 char *t; 73 int c; 74 75 setlocale(LC_ALL, ""); 76 77 if (pledge("stdio rpath getpw tty", NULL) == -1) 78 err(1, "pledge"); 79 80 mytty = ttyname(0); 81 /* strip any directory component */ 82 if ((t = strrchr(mytty, '/'))) 83 mytty = t + 1; 84 85 only_current_term = show_term = show_idle = show_labels = 0; 86 show_quick = 0; 87 while ((c = getopt(argc, argv, "HmqTu")) != -1) { 88 switch (c) { 89 case 'H': 90 show_labels = 1; 91 break; 92 case 'm': 93 only_current_term = 1; 94 break; 95 case 'q': 96 show_quick = 1; 97 break; 98 case 'T': 99 show_term = 1; 100 break; 101 case 'u': 102 show_idle = 1; 103 break; 104 default: 105 usage(); 106 /* NOTREACHED */ 107 } 108 } 109 argc -= optind; 110 argv += optind; 111 112 if (show_quick) { 113 only_current_term = show_term = show_idle = show_labels = 0; 114 } 115 116 if (show_term) 117 hostwidth -= 2; 118 if (show_idle) 119 hostwidth -= 6; 120 121 if (show_labels) 122 output_labels(); 123 124 switch (argc) { 125 case 0: /* who */ 126 ufp = file(_PATH_UTMP); 127 128 if (only_current_term) { 129 who_am_i(ufp); 130 } else if (show_quick) { 131 int count = 0; 132 133 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) { 134 if (*usr.ut_name && *usr.ut_line) { 135 (void)printf("%-*.*s ", NAME_WIDTH, 136 UT_NAMESIZE, usr.ut_name); 137 if ((++count % 8) == 0) 138 (void) printf("\n"); 139 } 140 } 141 if (count % 8) 142 (void) printf("\n"); 143 (void) printf ("# users=%d\n", count); 144 } else { 145 /* only entries with both name and line fields */ 146 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) 147 if (*usr.ut_name && *usr.ut_line) 148 output(&usr); 149 } 150 break; 151 case 1: /* who utmp_file */ 152 ufp = file(*argv); 153 154 if (only_current_term) { 155 who_am_i(ufp); 156 } else if (show_quick) { 157 int count = 0; 158 159 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) { 160 if (*usr.ut_name && *usr.ut_line) { 161 (void)printf("%-*.*s ", NAME_WIDTH, 162 UT_NAMESIZE, usr.ut_name); 163 if ((++count % 8) == 0) 164 (void) printf("\n"); 165 } 166 } 167 if (count % 8) 168 (void) printf("\n"); 169 (void) printf ("# users=%d\n", count); 170 } else { 171 /* all entries */ 172 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) 173 output(&usr); 174 } 175 break; 176 case 2: /* who am i */ 177 ufp = file(_PATH_UTMP); 178 who_am_i(ufp); 179 break; 180 default: 181 usage(); 182 /* NOTREACHED */ 183 } 184 exit(0); 185 } 186 187 void 188 who_am_i(FILE *ufp) 189 { 190 struct utmp usr; 191 struct passwd *pw; 192 193 /* search through the utmp and find an entry for this tty */ 194 if (mytty) { 195 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) 196 if (*usr.ut_name && !strcmp(usr.ut_line, mytty)) { 197 output(&usr); 198 return; 199 } 200 /* well, at least we know what the tty is */ 201 (void)strncpy(usr.ut_line, mytty, UT_LINESIZE); 202 } else 203 (void)strncpy(usr.ut_line, "tty??", UT_LINESIZE); 204 205 pw = getpwuid(getuid()); 206 (void)strncpy(usr.ut_name, pw ? pw->pw_name : "?", UT_NAMESIZE); 207 (void)time(&usr.ut_time); 208 *usr.ut_host = '\0'; 209 output(&usr); 210 } 211 212 void 213 output(struct utmp *up) 214 { 215 struct stat sb; 216 char line[sizeof(_PATH_DEV) + sizeof (up->ut_line)]; 217 char state = '?'; 218 static time_t now = 0; 219 time_t idle = 0; 220 221 if (show_term || show_idle) { 222 if (now == 0) 223 time(&now); 224 225 memset(line, 0, sizeof line); 226 strlcpy(line, _PATH_DEV, sizeof line); 227 strlcat(line, up->ut_line, sizeof line); 228 229 if (stat(line, &sb) == 0) { 230 state = (sb.st_mode & 020) ? '+' : '-'; 231 idle = now - sb.st_atime; 232 } else { 233 state = '?'; 234 idle = 0; 235 } 236 237 } 238 239 (void)printf("%-*.*s ", NAME_WIDTH, UT_NAMESIZE, up->ut_name); 240 241 if (show_term) { 242 (void)printf("%c ", state); 243 } 244 245 (void)printf("%-*.*s ", UT_LINESIZE, UT_LINESIZE, up->ut_line); 246 (void)printf("%.12s ", ctime(&up->ut_time) + 4); 247 248 if (show_idle) { 249 if (idle < 60) 250 (void)printf(" . "); 251 else if (idle < (24 * 60 * 60)) 252 (void)printf("%02d:%02d ", 253 ((int)idle / (60 * 60)), 254 ((int)idle % (60 * 60)) / 60); 255 else 256 (void)printf(" old "); 257 } 258 259 if (*up->ut_host) 260 printf(" (%.*s)", hostwidth, up->ut_host); 261 (void)putchar('\n'); 262 } 263 264 void 265 output_labels(void) 266 { 267 (void)printf("%-*.*s ", NAME_WIDTH, UT_NAMESIZE, "USER"); 268 269 if (show_term) 270 (void)printf("S "); 271 272 (void)printf("%-*.*s ", UT_LINESIZE, UT_LINESIZE, "LINE"); 273 (void)printf("WHEN "); 274 275 if (show_idle) 276 (void)printf("IDLE "); 277 278 (void)printf(" %.*s", hostwidth, "FROM"); 279 280 (void)putchar('\n'); 281 } 282 283 FILE * 284 file(char *name) 285 { 286 FILE *ufp; 287 288 if (!(ufp = fopen(name, "r"))) { 289 err(1, "%s", name); 290 /* NOTREACHED */ 291 } 292 if (show_term || show_idle) { 293 if (pledge("stdio rpath getpw", NULL) == -1) 294 err(1, "pledge"); 295 } else { 296 if (pledge("stdio getpw", NULL) == -1) 297 err(1, "pledge"); 298 } 299 return(ufp); 300 } 301 302 void 303 usage(void) 304 { 305 (void)fprintf(stderr, "usage: who [-HmqTu] [file]\n who am i\n"); 306 exit(1); 307 } 308