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