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