Print this page
10142 smatch fix for who
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/who/who.c
+++ new/usr/src/cmd/who/who.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
22 22 /* All Rights Reserved */
↓ open down ↓ |
22 lines elided |
↑ open up ↑ |
23 23
24 24
25 25 /*
26 26 * Copyright (c) 2013 Gary Mills
27 27 *
28 28 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
29 29 * Use is subject to license terms.
30 30 */
31 31
32 32 /*
33 + * Copyright (c) 2018, Joyent, Inc.
34 + */
35 +
36 +/*
33 37 * This program analyzes information found in /var/adm/utmpx
34 38 *
35 39 * Additionally information is gathered from /etc/inittab
36 40 * if requested.
37 41 *
38 42 *
39 43 * Syntax:
40 44 *
41 45 * who am i Displays info on yourself
42 46 *
43 47 * who -a Displays information about All
44 48 * entries in /var/adm/utmpx
45 49 *
46 50 * who -b Displays info on last boot
47 51 *
48 52 * who -d Displays info on DEAD PROCESSES
49 53 *
50 54 * who -H Displays HEADERS for output
51 55 *
52 56 * who -l Displays info on LOGIN entries
53 57 *
54 58 * who -m Same as who am i
55 59 *
56 60 * who -p Displays info on PROCESSES spawned by init
57 61 *
58 62 * who -q Displays short information on
59 63 * current users who LOGGED ON
60 64 *
61 65 * who -r Displays info of current run-level
62 66 *
63 67 * who -s Displays requested info in SHORT form
64 68 *
65 69 * who -t Displays info on TIME changes
66 70 *
67 71 * who -T Displays writeability of each user
68 72 * (+ writeable, - non-writeable, ? hung)
69 73 *
70 74 * who -u Displays LONG info on users
71 75 * who have LOGGED ON
72 76 */
73 77
74 78 #define DATE_FMT "%b %e %H:%M"
75 79
76 80 /*
77 81 * %b Abbreviated month name
78 82 * %e Day of month
79 83 * %H hour (24-hour clock)
80 84 * %M minute
81 85 */
82 86 #include <errno.h>
83 87 #include <fcntl.h>
84 88 #include <stdio.h>
85 89 #include <string.h>
86 90 #include <sys/types.h>
87 91 #include <unistd.h>
88 92 #include <stdlib.h>
89 93 #include <sys/stat.h>
90 94 #include <time.h>
91 95 #include <utmpx.h>
92 96 #include <locale.h>
93 97 #include <pwd.h>
94 98 #include <limits.h>
95 99
96 100 static void process(void);
97 101 static void ck_file(char *);
98 102 static void dump(void);
99 103
100 104 static struct utmpx *utmpp; /* pointer for getutxent() */
101 105
102 106 /*
103 107 * Use the full lengths from utmpx for user and line.
104 108 */
105 109 #define NMAX (sizeof (utmpp->ut_user))
106 110 #define LMAX (sizeof (utmpp->ut_line))
107 111
108 112 /* Print minimum field widths. */
109 113 #define LOGIN_WIDTH 8
110 114 #define LINE_WIDTH 12
111 115
112 116 static char comment[BUFSIZ]; /* holds inittab comment */
113 117 static char errmsg[BUFSIZ]; /* used in snprintf for errors */
114 118 static int fildes; /* file descriptor for inittab */
115 119 static int Hopt = 0; /* 1 = who -H */
116 120 static char *inittab; /* ptr to inittab contents */
117 121 static char *iinit; /* index into inittab */
118 122 static int justme = 0; /* 1 = who am i */
119 123 static struct tm *lptr; /* holds user login time */
120 124 static char *myname; /* pointer to invoker's name */
121 125 static char *mytty; /* holds device user is on */
122 126 static char nameval[sizeof (utmpp->ut_user) + 1]; /* invoker's name */
123 127 static int number = 8; /* number of users per -q line */
124 128 static int optcnt = 0; /* keeps count of options */
125 129 static char outbuf[BUFSIZ]; /* buffer for output */
126 130 static char *program; /* holds name of this program */
127 131 #ifdef XPG4
128 132 static int aopt = 0; /* 1 = who -a */
129 133 static int dopt = 0; /* 1 = who -d */
130 134 #endif /* XPG4 */
131 135 static int qopt = 0; /* 1 = who -q */
132 136 static int sopt = 0; /* 1 = who -s */
133 137 static struct stat stbuf; /* area for stat buffer */
134 138 static struct stat *stbufp; /* ptr to structure */
135 139 static int terse = 1; /* 1 = print terse msgs */
136 140 static int Topt = 0; /* 1 = who -T */
137 141 static time_t timnow; /* holds current time */
138 142 static int totlusrs = 0; /* cntr for users on system */
139 143 static int uopt = 0; /* 1 = who -u */
140 144 static char user[sizeof (utmpp->ut_user) + 1]; /* holds user name */
141 145 static int validtype[UTMAXTYPE+1]; /* holds valid types */
142 146 static int wrap; /* flag to indicate wrap */
143 147 static char time_buf[128]; /* holds date and time string */
144 148 static char *end; /* used in strtol for end pointer */
145 149
146 150 int
147 151 main(int argc, char **argv)
148 152 {
149 153 int goerr = 0; /* non-zero indicates cmd error */
150 154 int i;
151 155 int optsw; /* switch for while of getopt() */
152 156
153 157 (void) setlocale(LC_ALL, "");
154 158
155 159 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
156 160 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
157 161 #endif
158 162 (void) textdomain(TEXT_DOMAIN);
159 163
160 164 validtype[USER_PROCESS] = 1;
161 165 validtype[EMPTY] = 0;
162 166 stbufp = &stbuf;
163 167
164 168 /*
165 169 * Strip off path name of this command
166 170 */
167 171 for (i = strlen(argv[0]); i >= 0 && argv[0][i] != '/'; --i)
168 172 ;
169 173 if (i >= 0)
170 174 argv[0] += i+1;
171 175 program = argv[0];
172 176
173 177 /*
174 178 * Buffer stdout for speed
175 179 */
176 180 setbuf(stdout, outbuf);
177 181
178 182 /*
179 183 * Retrieve options specified on command line
180 184 * XCU4 - add -m option
181 185 */
182 186 while ((optsw = getopt(argc, argv, "abdHlmn:pqrstTu")) != EOF) {
183 187 optcnt++;
184 188 switch (optsw) {
185 189
186 190 case 'a':
187 191 optcnt += 7;
188 192 validtype[BOOT_TIME] = 1;
189 193 validtype[DEAD_PROCESS] = 1;
190 194 validtype[LOGIN_PROCESS] = 1;
191 195 validtype[INIT_PROCESS] = 1;
192 196 validtype[RUN_LVL] = 1;
193 197 validtype[OLD_TIME] = 1;
194 198 validtype[NEW_TIME] = 1;
195 199 validtype[USER_PROCESS] = 1;
196 200 #ifdef XPG4
197 201 aopt = 1;
198 202 #endif /* XPG4 */
199 203 uopt = 1;
200 204 Topt = 1;
201 205 if (!sopt) terse = 0;
202 206 break;
203 207
204 208 case 'b':
205 209 validtype[BOOT_TIME] = 1;
206 210 if (!uopt) validtype[USER_PROCESS] = 0;
207 211 break;
208 212
209 213 case 'd':
210 214 validtype[DEAD_PROCESS] = 1;
211 215 if (!uopt) validtype[USER_PROCESS] = 0;
212 216 #ifdef XPG4
213 217 dopt = 1;
214 218 #endif /* XPG4 */
215 219 break;
216 220
217 221 case 'H':
218 222 optcnt--; /* Don't count Header */
219 223 Hopt = 1;
220 224 break;
221 225
222 226 case 'l':
223 227 validtype[LOGIN_PROCESS] = 1;
224 228 if (!uopt) validtype[USER_PROCESS] = 0;
225 229 terse = 0;
226 230 break;
227 231 case 'm': /* New XCU4 option */
228 232 justme = 1;
229 233 break;
230 234
231 235 case 'n':
232 236 errno = 0;
233 237 number = strtol(optarg, &end, 10);
234 238 if (errno != 0 || *end != '\0') {
235 239 (void) fprintf(stderr, gettext(
236 240 "%s: Invalid numeric argument\n"),
237 241 program);
238 242 exit(1);
239 243 }
240 244 if (number < 1) {
241 245 (void) fprintf(stderr, gettext(
242 246 "%s: Number of users per line must "
243 247 "be at least 1\n"), program);
244 248 exit(1);
245 249 }
246 250 break;
247 251
248 252 case 'p':
249 253 validtype[INIT_PROCESS] = 1;
250 254 if (!uopt) validtype[USER_PROCESS] = 0;
251 255 break;
252 256
253 257 case 'q':
254 258 qopt = 1;
255 259 break;
256 260
257 261 case 'r':
258 262 validtype[RUN_LVL] = 1;
259 263 terse = 0;
260 264 if (!uopt) validtype[USER_PROCESS] = 0;
261 265 break;
262 266
263 267 case 's':
264 268 sopt = 1;
265 269 terse = 1;
266 270 break;
267 271
268 272 case 't':
269 273 validtype[OLD_TIME] = 1;
270 274 validtype[NEW_TIME] = 1;
271 275 if (!uopt) validtype[USER_PROCESS] = 0;
272 276 break;
273 277
274 278 case 'T':
275 279 Topt = 1;
276 280 #ifdef XPG4
277 281 terse = 1; /* XPG4 requires -T */
278 282 #else /* XPG4 */
279 283 terse = 0;
280 284 #endif /* XPG4 */
281 285 break;
282 286
283 287 case 'u':
284 288 uopt = 1;
285 289 validtype[USER_PROCESS] = 1;
286 290 if (!sopt) terse = 0;
287 291 break;
288 292
289 293 case '?':
290 294 goerr++;
291 295 break;
292 296 default:
↓ open down ↓ |
250 lines elided |
↑ open up ↑ |
293 297 break;
294 298 }
295 299 }
296 300 #ifdef XPG4
297 301 /*
298 302 * XCU4 changes - check for illegal sopt, Topt & aopt combination
299 303 */
300 304 if (sopt == 1) {
301 305 terse = 1;
302 306 if (Topt == 1 || aopt == 1)
303 - goerr++;
307 + goerr++;
304 308 }
305 309 #endif /* XPG4 */
306 310
307 311 if (goerr > 0) {
308 312 #ifdef XPG4
309 313 /*
310 314 * XCU4 - slightly different usage with -s -a & -T
311 315 */
312 316 (void) fprintf(stderr, gettext("\nUsage:\t%s"), program);
313 317 (void) fprintf(stderr,
314 318 gettext(" -s [-bdHlmpqrtu] [utmpx_like_file]\n"));
315 319
316 320 (void) fprintf(stderr, gettext(
317 321 "\t%s [-abdHlmpqrtTu] [utmpx_like_file]\n"), program);
318 322 #else /* XPG4 */
319 323 (void) fprintf(stderr, gettext(
320 324 "\nUsage:\t%s [-abdHlmpqrstTu] [utmpx_like_file]\n"),
321 325 program);
322 326 #endif /* XPG4 */
323 327 (void) fprintf(stderr,
324 328 gettext("\t%s -q [-n x] [utmpx_like_file]\n"), program);
325 329 (void) fprintf(stderr, gettext("\t%s [am i]\n"), program);
326 330 /*
327 331 * XCU4 changes - be explicit with "am i" options
328 332 */
329 333 (void) fprintf(stderr, gettext("\t%s [am I]\n"), program);
330 334 (void) fprintf(stderr, gettext(
331 335 "a\tall (bdlprtu options)\n"));
332 336 (void) fprintf(stderr, gettext("b\tboot time\n"));
333 337 (void) fprintf(stderr, gettext("d\tdead processes\n"));
334 338 (void) fprintf(stderr, gettext("H\tprint header\n"));
335 339 (void) fprintf(stderr, gettext("l\tlogin processes\n"));
336 340 (void) fprintf(stderr, gettext(
337 341 "n #\tspecify number of users per line for -q\n"));
338 342 (void) fprintf(stderr,
339 343 gettext("p\tprocesses other than getty or users\n"));
340 344 (void) fprintf(stderr, gettext("q\tquick %s\n"), program);
341 345 (void) fprintf(stderr, gettext("r\trun level\n"));
342 346 (void) fprintf(stderr, gettext(
343 347 "s\tshort form of %s (no time since last output or pid)\n"),
344 348 program);
345 349 (void) fprintf(stderr, gettext("t\ttime changes\n"));
346 350 (void) fprintf(stderr, gettext(
347 351 "T\tstatus of tty (+ writable, - not writable, "
348 352 "? hung)\n"));
349 353 (void) fprintf(stderr, gettext("u\tuseful information\n"));
350 354 (void) fprintf(stderr,
351 355 gettext("m\tinformation only about current terminal\n"));
352 356 (void) fprintf(stderr, gettext(
353 357 "am i\tinformation about current terminal "
354 358 "(same as -m)\n"));
355 359 (void) fprintf(stderr, gettext(
356 360 "am I\tinformation about current terminal "
357 361 "(same as -m)\n"));
358 362 exit(1);
359 363 }
360 364
361 365 /*
362 366 * XCU4: If -q option ignore all other options
363 367 */
364 368 if (qopt == 1) {
365 369 Hopt = 0;
366 370 sopt = 0;
367 371 Topt = 0;
368 372 uopt = 0;
369 373 justme = 0;
370 374 validtype[ACCOUNTING] = 0;
371 375 validtype[BOOT_TIME] = 0;
372 376 validtype[DEAD_PROCESS] = 0;
373 377 validtype[LOGIN_PROCESS] = 0;
374 378 validtype[INIT_PROCESS] = 0;
375 379 validtype[RUN_LVL] = 0;
376 380 validtype[OLD_TIME] = 0;
377 381 validtype[NEW_TIME] = 0;
378 382 validtype[USER_PROCESS] = 1;
379 383 }
380 384
381 385 if (argc == optind + 1) {
382 386 optcnt++;
383 387 ck_file(argv[optind]);
384 388 (void) utmpxname(argv[optind]);
385 389 }
386 390
387 391 /*
388 392 * Test for 'who am i' or 'who am I'
389 393 * XCU4 - check if justme was already set by -m option
390 394 */
391 395 if (justme == 1 || (argc == 3 && strcmp(argv[1], "am") == 0 &&
392 396 ((argv[2][0] == 'i' || argv[2][0] == 'I') &&
393 397 argv[2][1] == '\0'))) {
394 398 justme = 1;
395 399 myname = nameval;
396 400 (void) cuserid(myname);
397 401 if ((mytty = ttyname(fileno(stdin))) == NULL &&
398 402 (mytty = ttyname(fileno(stdout))) == NULL &&
399 403 (mytty = ttyname(fileno(stderr))) == NULL) {
400 404 (void) fprintf(stderr, gettext(
401 405 "Must be attached to terminal for 'am I' option\n"));
402 406 (void) fflush(stderr);
403 407 exit(1);
404 408 } else
405 409 mytty += 5; /* bump past "/dev/" */
406 410 }
407 411
408 412 if (!terse) {
409 413 if (Hopt)
410 414 (void) printf(gettext(
411 415 "NAME LINE TIME IDLE PID COMMENTS\n"));
412 416
413 417 timnow = time(0);
414 418
415 419 if ((fildes = open("/etc/inittab",
416 420 O_NONBLOCK|O_RDONLY)) == -1) {
417 421 (void) snprintf(errmsg, sizeof (errmsg),
418 422 gettext("%s: Cannot open /etc/inittab"), program);
419 423 perror(errmsg);
420 424 exit(errno);
421 425 }
422 426
423 427 if (fstat(fildes, stbufp) == -1) {
424 428 (void) snprintf(errmsg, sizeof (errmsg),
425 429 gettext("%s: Cannot stat /etc/inittab"), program);
426 430 perror(errmsg);
427 431 exit(errno);
428 432 }
429 433
430 434 if ((inittab = malloc(stbufp->st_size + 1)) == NULL) {
431 435 (void) snprintf(errmsg, sizeof (errmsg),
432 436 gettext("%s: Cannot allocate %ld bytes"),
433 437 program, stbufp->st_size);
434 438 perror(errmsg);
435 439 exit(errno);
436 440 }
437 441
438 442 if (read(fildes, inittab, stbufp->st_size)
439 443 != stbufp->st_size) {
440 444 (void) snprintf(errmsg, sizeof (errmsg),
441 445 gettext("%s: Error reading /etc/inittab"),
442 446 program);
443 447 perror(errmsg);
444 448 exit(errno);
445 449 }
446 450
447 451 inittab[stbufp->st_size] = '\0';
448 452 iinit = inittab;
449 453 } else {
450 454 if (Hopt) {
451 455 #ifdef XPG4
452 456 if (dopt) {
453 457 (void) printf(gettext(
454 458 "NAME LINE TIME COMMENTS\n"));
455 459 } else {
456 460 (void) printf(
457 461 gettext("NAME LINE TIME\n"));
458 462 }
459 463 #else /* XPG4 */
460 464 (void) printf(
461 465 gettext("NAME LINE TIME\n"));
462 466 #endif /* XPG4 */
463 467 }
464 468 }
465 469 process();
466 470
467 471 /*
468 472 * 'who -q' requires EOL upon exit,
469 473 * followed by total line
470 474 */
471 475 if (qopt)
472 476 (void) printf(gettext("\n# users=%d\n"), totlusrs);
473 477 return (0);
474 478 }
475 479
476 480 static void
477 481 dump()
478 482 {
479 483 char device[sizeof (utmpp->ut_line) + 1];
480 484 time_t hr;
481 485 time_t idle;
482 486 time_t min;
483 487 char path[sizeof (utmpp->ut_line) + 6];
484 488 int pexit;
485 489 int pterm;
486 490 int rc;
487 491 char w; /* writeability indicator */
488 492
489 493 /*
490 494 * Get and check user name
491 495 */
492 496 if (utmpp->ut_user[0] == '\0')
493 497 (void) strcpy(user, " .");
494 498 else {
495 499 (void) strncpy(user, utmpp->ut_user, sizeof (user));
496 500 user[sizeof (user) - 1] = '\0';
497 501 }
498 502 totlusrs++;
499 503
500 504 /*
501 505 * Do print in 'who -q' format
502 506 */
503 507 if (qopt) {
504 508 /*
505 509 * XCU4 - Use non user macro for correct user count
506 510 */
507 511 if (((totlusrs - 1) % number) == 0 && totlusrs > 1)
508 512 (void) printf("\n");
509 513 (void) printf("%-*.*s ", LOGIN_WIDTH, NMAX, user);
510 514 return;
511 515 }
512 516
513 517
514 518 pexit = (int)' ';
515 519 pterm = (int)' ';
516 520
517 521 /*
518 522 * Get exit info if applicable
519 523 */
520 524 if (utmpp->ut_type == RUN_LVL || utmpp->ut_type == DEAD_PROCESS) {
521 525 pterm = utmpp->ut_exit.e_termination;
522 526 pexit = utmpp->ut_exit.e_exit;
523 527 }
524 528
525 529 /*
526 530 * Massage ut_xtime field
527 531 */
528 532 lptr = localtime(&utmpp->ut_xtime);
529 533 (void) strftime(time_buf, sizeof (time_buf),
530 534 dcgettext(NULL, DATE_FMT, LC_TIME), lptr);
531 535
532 536 /*
533 537 * Get and massage device
534 538 */
535 539 if (utmpp->ut_line[0] == '\0')
536 540 (void) strcpy(device, " .");
537 541 else {
538 542 (void) strncpy(device, utmpp->ut_line,
539 543 sizeof (utmpp->ut_line));
540 544 device[sizeof (utmpp->ut_line)] = '\0';
541 545 }
542 546
543 547 /*
544 548 * Get writeability if requested
545 549 * XCU4 - only print + or - for user processes
546 550 */
547 551 if (Topt && (utmpp->ut_type == USER_PROCESS)) {
548 552 w = '-';
549 553 (void) strcpy(path, "/dev/");
550 554 (void) strncpy(path + 5, utmpp->ut_line,
551 555 sizeof (utmpp->ut_line));
552 556 path[5 + sizeof (utmpp->ut_line)] = '\0';
553 557
554 558 if ((rc = stat(path, stbufp)) == -1) w = '?';
555 559 else if ((stbufp->st_mode & S_IWOTH) ||
556 560 (stbufp->st_mode & S_IWGRP)) /* Check group & other */
557 561 w = '+';
558 562
559 563 } else
560 564 w = ' ';
561 565
562 566 /*
563 567 * Print the TERSE portion of the output
564 568 */
565 569 (void) printf("%-*.*s %c %-12s %s", LOGIN_WIDTH, NMAX, user,
566 570 w, device, time_buf);
567 571
568 572 if (!terse) {
569 573 /*
570 574 * Stat device for idle time
571 575 * (Don't complain if you can't)
572 576 */
573 577 rc = -1;
574 578 if (utmpp->ut_type == USER_PROCESS) {
575 579 (void) strcpy(path, "/dev/");
576 580 (void) strncpy(path + 5, utmpp->ut_line,
577 581 sizeof (utmpp->ut_line));
578 582 path[5 + sizeof (utmpp->ut_line)] = '\0';
579 583 rc = stat(path, stbufp);
580 584 }
581 585 if (rc != -1) {
582 586 idle = timnow - stbufp->st_mtime;
583 587 hr = idle/3600;
584 588 min = (unsigned)(idle/60)%60;
585 589 if (hr == 0 && min == 0)
586 590 (void) printf(gettext(" . "));
587 591 else {
588 592 if (hr < 24)
589 593 (void) printf(" %2d:%2.2d", (int)hr,
590 594 (int)min);
591 595 else
592 596 (void) printf(gettext(" old "));
593 597 }
594 598 }
595 599
596 600 /*
597 601 * Add PID for verbose output
598 602 */
599 603 if (utmpp->ut_type != BOOT_TIME &&
600 604 utmpp->ut_type != RUN_LVL &&
601 605 utmpp->ut_type != ACCOUNTING)
602 606 (void) printf(" %5ld", utmpp->ut_pid);
603 607
604 608 /*
605 609 * Handle /etc/inittab comment
606 610 */
607 611 if (utmpp->ut_type == DEAD_PROCESS) {
608 612 (void) printf(gettext(" id=%4.4s "),
609 613 utmpp->ut_id);
610 614 (void) printf(gettext("term=%-3d "), pterm);
611 615 (void) printf(gettext("exit=%d "), pexit);
612 616 } else if (utmpp->ut_type != INIT_PROCESS) {
613 617 /*
614 618 * Search for each entry in inittab
615 619 * string. Keep our place from
616 620 * search to search to try and
617 621 * minimize the work. Wrap once if needed
618 622 * for each entry.
619 623 */
620 624 wrap = 0;
621 625 /*
622 626 * Look for a line beginning with
623 627 * utmpp->ut_id
624 628 */
625 629 while ((rc = strncmp(utmpp->ut_id, iinit,
626 630 strcspn(iinit, ":"))) != 0) {
627 631 for (; *iinit != '\n'; iinit++)
628 632 ;
629 633 iinit++;
630 634
631 635 /*
632 636 * Wrap once if necessary to
633 637 * find entry in inittab
634 638 */
635 639 if (*iinit == '\0') {
636 640 if (!wrap) {
637 641 iinit = inittab;
638 642 wrap = 1;
639 643 }
640 644 }
641 645 }
642 646
643 647 if (*iinit != '\0') {
644 648 /*
645 649 * We found our entry
646 650 */
647 651 for (iinit++; *iinit != '#' &&
648 652 *iinit != '\n'; iinit++)
649 653 ;
650 654 if (*iinit == '#') {
651 655 for (iinit++; *iinit == ' ' ||
652 656 *iinit == '\t'; iinit++)
653 657 ;
654 658 for (rc = 0; *iinit != '\n'; iinit++)
655 659 comment[rc++] = *iinit;
656 660 comment[rc] = '\0';
657 661 } else
658 662 (void) strcpy(comment, " ");
659 663
660 664 (void) printf(" %s", comment);
661 665 } else
662 666 iinit = inittab; /* Reset pointer */
663 667 }
664 668 if (utmpp->ut_type == INIT_PROCESS)
665 669 (void) printf(gettext(" id=%4.4s"), utmpp->ut_id);
666 670 }
667 671 #ifdef XPG4
668 672 else
669 673 if (dopt && utmpp->ut_type == DEAD_PROCESS) {
670 674 (void) printf(gettext("\tterm=%-3d "), pterm);
671 675 (void) printf(gettext("exit=%d "), pexit);
672 676 }
673 677 #endif /* XPG4 */
674 678
675 679
676 680 /*
677 681 * Handle RUN_LVL process - If no alt. file - Only one!
678 682 */
679 683 if (utmpp->ut_type == RUN_LVL) {
680 684 (void) printf(" %c %5ld %c", pterm, utmpp->ut_pid,
681 685 pexit);
682 686 if (optcnt == 1 && !validtype[USER_PROCESS]) {
683 687 (void) printf("\n");
684 688 exit(0);
685 689 }
686 690 }
687 691
688 692 /*
689 693 * Handle BOOT_TIME process - If no alt. file - Only one!
690 694 */
↓ open down ↓ |
377 lines elided |
↑ open up ↑ |
691 695 if (utmpp->ut_type == BOOT_TIME) {
692 696 if (optcnt == 1 && !validtype[USER_PROCESS]) {
693 697 (void) printf("\n");
694 698 exit(0);
695 699 }
696 700 }
697 701
698 702 /*
699 703 * Get remote host from utmpx structure
700 704 */
701 - if (utmpp && utmpp->ut_host[0])
705 + if (utmpp->ut_host[0])
702 706 (void) printf("\t(%.*s)", sizeof (utmpp->ut_host),
703 707 utmpp->ut_host);
704 708
705 709 /*
706 710 * Now, put on the trailing EOL
707 711 */
708 712 (void) printf("\n");
709 713 }
710 714
711 715 static void
712 716 process()
713 717 {
714 718 struct passwd *pwp;
715 719 int i = 0;
716 720 char *ttname;
717 721
718 722 /*
719 723 * Loop over each entry in /var/adm/utmpx
720 724 */
721 725
722 726 setutxent();
723 727 while ((utmpp = getutxent()) != NULL) {
724 728 #ifdef DEBUG
725 729 (void) printf(
726 730 "ut_user '%s'\nut_id '%s'\nut_line '%s'\nut_type '%d'\n\n",
727 731 utmpp->ut_user, utmpp->ut_id, utmpp->ut_line, utmpp->ut_type);
728 732 #endif
729 733 if (utmpp->ut_type <= UTMAXTYPE) {
730 734 /*
731 735 * Handle "am i"
732 736 */
733 737 if (justme) {
734 738 if (strncmp(myname, utmpp->ut_user,
735 739 sizeof (utmpp->ut_user)) == 0 &&
736 740 strncmp(mytty, utmpp->ut_line,
737 741 sizeof (utmpp->ut_line)) == 0 &&
738 742 utmpp->ut_type == USER_PROCESS) {
739 743 /*
740 744 * we have have found ourselves
741 745 * in the utmp file and the entry
742 746 * is a user process, this is not
743 747 * meaningful otherwise
744 748 *
745 749 */
746 750
747 751 dump();
748 752 exit(0);
749 753 }
750 754 continue;
751 755 }
752 756
753 757 /*
754 758 * Print the line if we want it
755 759 */
756 760 if (validtype[utmpp->ut_type]) {
757 761 #ifdef XPG4
758 762 if (utmpp->ut_type == LOGIN_PROCESS) {
759 763 if ((utmpp->ut_line[0] == '\0') ||
760 764 (strcmp(utmpp->ut_user,
761 765 "LOGIN") != 0))
762 766 continue;
763 767 }
764 768 #endif /* XPG4 */
765 769 dump();
766 770 }
767 771 } else {
768 772 (void) fprintf(stderr,
769 773 gettext("%s: Error --- entry has ut_type "
770 774 "of %d\n"), program, utmpp->ut_type);
771 775 (void) fprintf(stderr,
772 776 gettext(" when maximum is %d\n"), UTMAXTYPE);
773 777 }
774 778 }
775 779
776 780 /*
777 781 * If justme is set at this point than the utmp entry
778 782 * was not found.
779 783 */
780 784 if (justme) {
781 785 static struct utmpx utmpt;
782 786
783 787 pwp = getpwuid(geteuid());
784 788 if (pwp != NULL)
785 789 while (i < (int)sizeof (utmpt.ut_user) &&
786 790 *pwp->pw_name != 0)
787 791 utmpt.ut_user[i++] = *pwp->pw_name++;
788 792
789 793 ttname = ttyname(1);
790 794
791 795 i = 0;
792 796 if (ttname != NULL)
793 797 while (i < (int)sizeof (utmpt.ut_line) &&
794 798 *ttname != 0)
795 799 utmpt.ut_line[i++] = *ttname++;
796 800
797 801 utmpt.ut_id[0] = 0;
798 802 utmpt.ut_pid = getpid();
799 803 utmpt.ut_type = USER_PROCESS;
800 804 (void) time(&utmpt.ut_xtime);
801 805 utmpp = &utmpt;
802 806 dump();
803 807 exit(0);
804 808 }
805 809 }
806 810
807 811 /*
808 812 * This routine checks the following:
809 813 *
810 814 * 1. File exists
811 815 *
812 816 * 2. We have read permissions
813 817 *
814 818 * 3. It is a multiple of utmp entries in size
815 819 *
816 820 * Failing any of these conditions causes who(1) to
817 821 * abort processing.
818 822 *
819 823 * 4. If file is empty we exit right away as there
820 824 * is no info to report on.
821 825 *
822 826 * This routine does not check utmpx files.
823 827 */
824 828 static void
825 829 ck_file(char *name)
826 830 {
827 831 struct stat sbuf;
828 832 int rc;
829 833
830 834 /*
831 835 * Does file exist? Do stat to check, and save structure
832 836 * so that we can check on the file's size later on.
833 837 */
834 838 if ((rc = stat(name, &sbuf)) == -1) {
835 839 (void) snprintf(errmsg, sizeof (errmsg),
836 840 gettext("%s: Cannot stat file '%s'"), program, name);
837 841 perror(errmsg);
838 842 exit(1);
839 843 }
840 844
841 845 /*
842 846 * The only real way we can be sure we can access the
843 847 * file is to try. If we succeed then we close it.
844 848 */
845 849 if (access(name, R_OK) < 0) {
846 850 (void) snprintf(errmsg, sizeof (errmsg),
847 851 gettext("%s: Cannot open file '%s'"), program, name);
848 852 perror(errmsg);
849 853 exit(1);
850 854 }
851 855
852 856 /*
853 857 * If the file is empty, we are all done.
854 858 */
855 859 if (!sbuf.st_size)
856 860 exit(0);
857 861
858 862 /*
859 863 * Make sure the file is a utmp file.
860 864 * We can only check for size being a multiple of
861 865 * utmp structures in length.
862 866 */
863 867 rc = sbuf.st_size % (int)sizeof (struct utmpx);
864 868 if (rc) {
865 869 (void) fprintf(stderr, gettext("%s: File '%s' is not "
866 870 "a utmpx file\n"), program, name);
867 871 exit(1);
868 872 }
869 873 }
↓ open down ↓ |
158 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX