1 /* $OpenBSD: who.c,v 1.27 2015/10/21 16:06:57 millert 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", NULL) == -1) 78 err(1, "pledge"); 79 80 if ((mytty = ttyname(0))) { 81 /* strip any directory component */ 82 if ((t = strrchr(mytty, '/'))) 83 mytty = t + 1; 84 } 85 86 only_current_term = show_term = show_idle = show_labels = 0; 87 show_quick = 0; 88 while ((c = getopt(argc, argv, "HmqTu")) != -1) { 89 switch (c) { 90 case 'H': 91 show_labels = 1; 92 break; 93 case 'm': 94 only_current_term = 1; 95 break; 96 case 'q': 97 show_quick = 1; 98 break; 99 case 'T': 100 show_term = 1; 101 break; 102 case 'u': 103 show_idle = 1; 104 break; 105 default: 106 usage(); 107 /* NOTREACHED */ 108 } 109 } 110 argc -= optind; 111 argv += optind; 112 113 if (show_quick) { 114 only_current_term = show_term = show_idle = show_labels = 0; 115 } 116 117 if (show_term) 118 hostwidth -= 2; 119 if (show_idle) 120 hostwidth -= 6; 121 122 if (show_labels) 123 output_labels(); 124 125 switch (argc) { 126 case 0: /* who */ 127 ufp = file(_PATH_UTMP); 128 129 if (only_current_term) { 130 who_am_i(ufp); 131 } else if (show_quick) { 132 int count = 0; 133 134 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) { 135 if (*usr.ut_name && *usr.ut_line) { 136 (void)printf("%-*.*s ", NAME_WIDTH, 137 UT_NAMESIZE, usr.ut_name); 138 if ((++count % 8) == 0) 139 (void) printf("\n"); 140 } 141 } 142 if (count % 8) 143 (void) printf("\n"); 144 (void) printf ("# users=%d\n", count); 145 } else { 146 /* only entries with both name and line fields */ 147 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) 148 if (*usr.ut_name && *usr.ut_line) 149 output(&usr); 150 } 151 break; 152 case 1: /* who utmp_file */ 153 ufp = file(*argv); 154 155 if (only_current_term) { 156 who_am_i(ufp); 157 } else if (show_quick) { 158 int count = 0; 159 160 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) { 161 if (*usr.ut_name && *usr.ut_line) { 162 (void)printf("%-*.*s ", NAME_WIDTH, 163 UT_NAMESIZE, usr.ut_name); 164 if ((++count % 8) == 0) 165 (void) printf("\n"); 166 } 167 } 168 if (count % 8) 169 (void) printf("\n"); 170 (void) printf ("# users=%d\n", count); 171 } else { 172 /* all entries */ 173 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) 174 output(&usr); 175 } 176 break; 177 case 2: /* who am i */ 178 ufp = file(_PATH_UTMP); 179 who_am_i(ufp); 180 break; 181 default: 182 usage(); 183 /* NOTREACHED */ 184 } 185 exit(0); 186 } 187 188 void 189 who_am_i(FILE *ufp) 190 { 191 struct utmp usr; 192 struct passwd *pw; 193 194 /* search through the utmp and find an entry for this tty */ 195 if (mytty) { 196 while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) 197 if (*usr.ut_name && !strcmp(usr.ut_line, mytty)) { 198 output(&usr); 199 return; 200 } 201 /* well, at least we know what the tty is */ 202 (void)strncpy(usr.ut_line, mytty, UT_LINESIZE); 203 } else 204 (void)strncpy(usr.ut_line, "tty??", UT_LINESIZE); 205 206 pw = getpwuid(getuid()); 207 (void)strncpy(usr.ut_name, pw ? pw->pw_name : "?", UT_NAMESIZE); 208 (void)time(&usr.ut_time); 209 *usr.ut_host = '\0'; 210 output(&usr); 211 } 212 213 void 214 output(struct utmp *up) 215 { 216 struct stat sb; 217 char line[sizeof(_PATH_DEV) + sizeof (up->ut_line)]; 218 char state = '?'; 219 static time_t now = 0; 220 time_t idle = 0; 221 222 if (show_term || show_idle) { 223 if (now == 0) 224 time(&now); 225 226 memset(line, 0, sizeof line); 227 strlcpy(line, _PATH_DEV, sizeof line); 228 strlcat(line, up->ut_line, sizeof line); 229 230 if (stat(line, &sb) == 0) { 231 state = (sb.st_mode & 020) ? '+' : '-'; 232 idle = now - sb.st_atime; 233 } else { 234 state = '?'; 235 idle = 0; 236 } 237 238 } 239 240 (void)printf("%-*.*s ", NAME_WIDTH, UT_NAMESIZE, up->ut_name); 241 242 if (show_term) { 243 (void)printf("%c ", state); 244 } 245 246 (void)printf("%-*.*s ", UT_LINESIZE, UT_LINESIZE, up->ut_line); 247 (void)printf("%.12s ", ctime(&up->ut_time) + 4); 248 249 if (show_idle) { 250 if (idle < 60) 251 (void)printf(" . "); 252 else if (idle < (24 * 60 * 60)) 253 (void)printf("%02d:%02d ", 254 ((int)idle / (60 * 60)), 255 ((int)idle % (60 * 60)) / 60); 256 else 257 (void)printf(" old "); 258 } 259 260 if (*up->ut_host) 261 printf(" (%.*s)", hostwidth, up->ut_host); 262 (void)putchar('\n'); 263 } 264 265 void 266 output_labels(void) 267 { 268 (void)printf("%-*.*s ", NAME_WIDTH, UT_NAMESIZE, "USER"); 269 270 if (show_term) 271 (void)printf("S "); 272 273 (void)printf("%-*.*s ", UT_LINESIZE, UT_LINESIZE, "LINE"); 274 (void)printf("WHEN "); 275 276 if (show_idle) 277 (void)printf("IDLE "); 278 279 (void)printf(" %.*s", hostwidth, "FROM"); 280 281 (void)putchar('\n'); 282 } 283 284 FILE * 285 file(char *name) 286 { 287 FILE *ufp; 288 289 if (!(ufp = fopen(name, "r"))) { 290 err(1, "%s", name); 291 /* NOTREACHED */ 292 } 293 if (show_term || show_idle) { 294 if (pledge("stdio rpath getpw", NULL) == -1) 295 err(1, "pledge"); 296 } else { 297 if (pledge("stdio getpw", NULL) == -1) 298 err(1, "pledge"); 299 } 300 return(ufp); 301 } 302 303 void 304 usage(void) 305 { 306 (void)fprintf(stderr, "usage: who [-HmqTu] [file]\n who am i\n"); 307 exit(1); 308 } 309