Print this page
3124 Remove any existing references to utmp, use utmpx instead
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/w/w.c
+++ new/usr/src/cmd/w/w.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 /*
22 22 * Copyright (c) 2013 Gary Mills
23 23 *
24 24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
25 25 * Use is subject to license terms.
26 26 */
27 27
28 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 29 /* All Rights Reserved */
30 30
31 31 /*
32 32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 33 * The Regents of the University of California
34 34 * All Rights Reserved
35 35 *
36 36 * University Acknowledgment- Portions of this document are derived from
37 37 * software developed by the University of California, Berkeley, and its
38 38 * contributors.
39 39 */
40 40
41 41 /*
42 42 * This is the new w command which takes advantage of
43 43 * the /proc interface to gain access to the information
44 44 * of all the processes currently on the system.
45 45 *
46 46 * This program also implements 'uptime'.
47 47 *
48 48 * Maintenance note:
49 49 *
50 50 * Much of this code is replicated in whodo.c. If you're
51 51 * fixing bugs here, then you should probably fix 'em there too.
52 52 */
53 53
54 54 #include <stdio.h>
55 55 #include <string.h>
56 56 #include <stdarg.h>
57 57 #include <stdlib.h>
58 58 #include <ctype.h>
59 59 #include <fcntl.h>
60 60 #include <time.h>
61 61 #include <errno.h>
62 62 #include <sys/types.h>
63 63 #include <utmpx.h>
64 64 #include <sys/stat.h>
65 65 #include <dirent.h>
66 66 #include <procfs.h> /* /proc header file */
67 67 #include <locale.h>
68 68 #include <unistd.h>
69 69 #include <sys/loadavg.h>
70 70 #include <limits.h>
71 71 #include <priv_utils.h>
72 72
73 73 /*
74 74 * Use the full lengths from utmpx for user and line.
75 75 */
76 76 static struct utmpx dummy;
77 77 #define NMAX (sizeof (dummy.ut_user))
78 78 #define LMAX (sizeof (dummy.ut_line))
79 79
80 80 /* Print minimum field widths. */
81 81 #define LOGIN_WIDTH 8
82 82 #define LINE_WIDTH 8
83 83
84 84 #define DIV60(t) ((t+30)/60) /* x/60 rounded */
85 85
86 86 #ifdef ERR
87 87 #undef ERR
88 88 #endif
89 89 #define ERR (-1)
90 90
91 91 #define HSIZE 256 /* size of process hash table */
92 92 #define PROCDIR "/proc"
93 93 #define INITPROCESS (pid_t)1 /* init process pid */
94 94 #define NONE 'n' /* no state */
95 95 #define RUNNING 'r' /* runnable process */
96 96 #define ZOMBIE 'z' /* zombie process */
97 97 #define VISITED 'v' /* marked node as visited */
98 98 #define PRINTF(a) if (printf a < 0) { \
99 99 perror((gettext("%s: printf failed"), prog)); \
100 100 exit(1); }
101 101
102 102 struct uproc {
103 103 pid_t p_upid; /* process id */
104 104 char p_state; /* numeric value of process state */
105 105 dev_t p_ttyd; /* controlling tty of process */
106 106 time_t p_time; /* seconds of user & system time */
107 107 time_t p_ctime; /* seconds of child user & sys time */
108 108 int p_igintr; /* 1 = ignores SIGQUIT and SIGINT */
109 109 char p_comm[PRARGSZ+1]; /* command */
110 110 char p_args[PRARGSZ+1]; /* command line arguments */
111 111 struct uproc *p_child, /* first child pointer */
112 112 *p_sibling, /* sibling pointer */
113 113 *p_pgrpl, /* pgrp link */
114 114 *p_link; /* hash table chain pointer */
115 115 };
116 116
117 117 /*
118 118 * define hash table for struct uproc
119 119 * Hash function uses process id
120 120 * and the size of the hash table(HSIZE)
121 121 * to determine process index into the table.
122 122 */
123 123 static struct uproc pr_htbl[HSIZE];
124 124
125 125 static struct uproc *findhash(pid_t);
126 126 static time_t findidle(char *);
127 127 static void clnarglist(char *);
128 128 static void showtotals(struct uproc *);
129 129 static void calctotals(struct uproc *);
130 130 static void prttime(time_t, int);
131 131 static void prtat(time_t *time);
132 132
133 133 static char *prog; /* pointer to invocation name */
134 134 static int header = 1; /* true if -h flag: don't print heading */
135 135 static int lflag = 1; /* set if -l flag; 0 for -s flag: short form */
136 136 static char *sel_user; /* login of particular user selected */
137 137 static char firstchar; /* first char of name of prog invoked as */
138 138 static int login; /* true if invoked as login shell */
139 139 static time_t now; /* current time of day */
140 140 static time_t uptime; /* time of last reboot & elapsed time since */
141 141 static int nusers; /* number of users logged in now */
142 142 static time_t idle; /* number of minutes user is idle */
143 143 static time_t jobtime; /* total cpu time visible */
144 144 static char doing[520]; /* process attached to terminal */
145 145 static time_t proctime; /* cpu time of process in doing */
146 146 static pid_t curpid, empty;
147 147 static int add_times; /* boolean: add the cpu times or not */
148 148
149 149 #if SIGQUIT > SIGINT
150 150 #define ACTSIZE SIGQUIT
151 151 #else
152 152 #define ACTSIZE SIGINT
153 153 #endif
154 154
155 155 int
156 156 main(int argc, char *argv[])
157 157 {
158 158 struct utmpx *ut;
159 159 struct utmpx *utmpbegin;
160 160 struct utmpx *utmpend;
161 161 struct utmpx *utp;
162 162 struct uproc *up, *parent, *pgrp;
163 163 struct psinfo info;
164 164 struct sigaction actinfo[ACTSIZE];
165 165 struct pstatus statinfo;
166 166 size_t size;
167 167 struct stat sbuf;
168 168 DIR *dirp;
169 169 struct dirent *dp;
170 170 char pname[64];
171 171 char *fname;
172 172 int procfd;
173 173 char *cp;
174 174 int i;
175 175 int days, hrs, mins;
176 176 int entries;
177 177 double loadavg[3];
178 178
179 179 /*
180 180 * This program needs the proc_owner privilege
181 181 */
182 182 (void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_PROC_OWNER,
183 183 (char *)NULL);
184 184
185 185 (void) setlocale(LC_ALL, "");
186 186 #if !defined(TEXT_DOMAIN)
187 187 #define TEXT_DOMAIN "SYS_TEST"
188 188 #endif
189 189 (void) textdomain(TEXT_DOMAIN);
190 190
191 191 login = (argv[0][0] == '-');
192 192 cp = strrchr(argv[0], '/');
193 193 firstchar = login ? argv[0][1] : (cp == 0) ? argv[0][0] : cp[1];
194 194 prog = argv[0];
195 195
196 196 while (argc > 1) {
197 197 if (argv[1][0] == '-') {
198 198 for (i = 1; argv[1][i]; i++) {
199 199 switch (argv[1][i]) {
200 200
201 201 case 'h':
202 202 header = 0;
203 203 break;
204 204
205 205 case 'l':
206 206 lflag++;
207 207 break;
208 208 case 's':
209 209 lflag = 0;
210 210 break;
211 211
212 212 case 'u':
213 213 case 'w':
214 214 firstchar = argv[1][i];
215 215 break;
216 216
217 217 default:
218 218 (void) fprintf(stderr, gettext(
219 219 "%s: bad flag %s\n"),
220 220 prog, argv[1]);
221 221 exit(1);
222 222 }
223 223 }
224 224 } else {
225 225 if (!isalnum(argv[1][0]) || argc > 2) {
↓ open down ↓ |
225 lines elided |
↑ open up ↑ |
226 226 (void) fprintf(stderr, gettext(
227 227 "usage: %s [ -hlsuw ] [ user ]\n"), prog);
228 228 exit(1);
229 229 } else
230 230 sel_user = argv[1];
231 231 }
232 232 argc--; argv++;
233 233 }
234 234
235 235 /*
236 - * read the UTMP_FILE (contains information about each logged in user)
236 + * read the UTMPX_FILE (contains information about each logged in user)
237 237 */
238 238 if (stat(UTMPX_FILE, &sbuf) == ERR) {
239 239 (void) fprintf(stderr, gettext("%s: stat error of %s: %s\n"),
240 240 prog, UTMPX_FILE, strerror(errno));
241 241 exit(1);
242 242 }
243 243 entries = sbuf.st_size / sizeof (struct futmpx);
244 244 size = sizeof (struct utmpx) * entries;
245 245 if ((ut = malloc(size)) == NULL) {
246 246 (void) fprintf(stderr, gettext("%s: malloc error of %s: %s\n"),
247 247 prog, UTMPX_FILE, strerror(errno));
248 248 exit(1);
249 249 }
250 250
251 251 (void) utmpxname(UTMPX_FILE);
252 252
253 253 utmpbegin = ut;
254 254 utmpend = (struct utmpx *)((char *)utmpbegin + size);
255 255
256 256 setutxent();
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
257 257 while ((ut < utmpend) && ((utp = getutxent()) != NULL))
258 258 (void) memcpy(ut++, utp, sizeof (*ut));
259 259 endutxent();
260 260
261 261 (void) time(&now); /* get current time */
262 262
263 263 if (header) { /* print a header */
264 264 prtat(&now);
265 265 for (ut = utmpbegin; ut < utmpend; ut++) {
266 266 if (ut->ut_type == USER_PROCESS) {
267 - if (!nonuser(*ut))
267 + if (!nonuserx(*ut))
268 268 nusers++;
269 269 } else if (ut->ut_type == BOOT_TIME) {
270 270 uptime = now - ut->ut_xtime;
271 271 uptime += 30;
272 272 days = uptime / (60*60*24);
273 273 uptime %= (60*60*24);
274 274 hrs = uptime / (60*60);
275 275 uptime %= (60*60);
276 276 mins = uptime / 60;
277 277
278 278 PRINTF((gettext("up")));
279 279 if (days > 0)
280 280 PRINTF((gettext(
281 281 " %d day(s),"), days));
282 282 if (hrs > 0 && mins > 0) {
283 283 PRINTF((" %2d:%02d,", hrs, mins));
284 284 } else {
285 285 if (hrs > 0)
286 286 PRINTF((gettext(
287 287 " %d hr(s),"), hrs));
288 288 if (mins > 0)
289 289 PRINTF((gettext(
290 290 " %d min(s),"), mins));
291 291 }
292 292 }
293 293 }
294 294
295 295 ut = utmpbegin; /* rewind utmp data */
296 296 PRINTF((((nusers == 1) ?
297 297 gettext(" %d user") : gettext(" %d users")), nusers));
298 298 /*
299 299 * Print 1, 5, and 15 minute load averages.
300 300 */
301 301 (void) getloadavg(loadavg, 3);
302 302 PRINTF((gettext(", load average: %.2f, %.2f, %.2f\n"),
303 303 loadavg[LOADAVG_1MIN], loadavg[LOADAVG_5MIN],
304 304 loadavg[LOADAVG_15MIN]));
305 305
306 306 if (firstchar == 'u') /* uptime command */
307 307 exit(0);
308 308
309 309 if (lflag) {
310 310 PRINTF((dcgettext(NULL, "User tty "
311 311 "login@ idle JCPU PCPU what\n",
312 312 LC_TIME)));
313 313 } else {
314 314 PRINTF((dcgettext(NULL,
315 315 "User tty idle what\n",
316 316 LC_TIME)));
317 317 }
318 318
319 319 if (fflush(stdout) == EOF) {
320 320 perror((gettext("%s: fflush failed\n"), prog));
321 321 exit(1);
322 322 }
323 323 }
324 324
325 325 /*
326 326 * loop through /proc, reading info about each process
327 327 * and build the parent/child tree
328 328 */
329 329 if (!(dirp = opendir(PROCDIR))) {
330 330 (void) fprintf(stderr, gettext("%s: could not open %s: %s\n"),
331 331 prog, PROCDIR, strerror(errno));
332 332 exit(1);
333 333 }
334 334
335 335 while ((dp = readdir(dirp)) != NULL) {
336 336 if (dp->d_name[0] == '.')
337 337 continue;
338 338 retry:
339 339 (void) sprintf(pname, "%s/%s/", PROCDIR, dp->d_name);
340 340 fname = pname + strlen(pname);
341 341 (void) strcpy(fname, "psinfo");
342 342 if ((procfd = open(pname, O_RDONLY)) < 0)
343 343 continue;
344 344 if (read(procfd, &info, sizeof (info)) != sizeof (info)) {
345 345 int err = errno;
346 346 (void) close(procfd);
347 347 if (err == EAGAIN)
348 348 goto retry;
349 349 if (err != ENOENT)
350 350 (void) fprintf(stderr, gettext(
351 351 "%s: read() failed on %s: %s \n"),
352 352 prog, pname, strerror(err));
353 353 continue;
354 354 }
355 355 (void) close(procfd);
356 356
357 357 up = findhash(info.pr_pid);
358 358 up->p_ttyd = info.pr_ttydev;
359 359 up->p_state = (info.pr_nlwp == 0? ZOMBIE : RUNNING);
360 360 up->p_time = 0;
361 361 up->p_ctime = 0;
362 362 up->p_igintr = 0;
363 363 (void) strncpy(up->p_comm, info.pr_fname,
364 364 sizeof (info.pr_fname));
365 365 up->p_args[0] = 0;
366 366
367 367 if (up->p_state != NONE && up->p_state != ZOMBIE) {
368 368 (void) strcpy(fname, "status");
369 369
370 370 /* now we need the proc_owner privilege */
371 371 (void) __priv_bracket(PRIV_ON);
372 372
373 373 procfd = open(pname, O_RDONLY);
374 374
375 375 /* drop proc_owner privilege after open */
376 376 (void) __priv_bracket(PRIV_OFF);
377 377
378 378 if (procfd < 0)
379 379 continue;
380 380
381 381 if (read(procfd, &statinfo, sizeof (statinfo))
382 382 != sizeof (statinfo)) {
383 383 int err = errno;
384 384 (void) close(procfd);
385 385 if (err == EAGAIN)
386 386 goto retry;
387 387 if (err != ENOENT)
388 388 (void) fprintf(stderr, gettext(
389 389 "%s: read() failed on %s: %s \n"),
390 390 prog, pname, strerror(err));
391 391 continue;
392 392 }
393 393 (void) close(procfd);
394 394
395 395 up->p_time = statinfo.pr_utime.tv_sec +
396 396 statinfo.pr_stime.tv_sec; /* seconds */
397 397 up->p_ctime = statinfo.pr_cutime.tv_sec +
398 398 statinfo.pr_cstime.tv_sec;
399 399
400 400 (void) strcpy(fname, "sigact");
401 401
402 402 /* now we need the proc_owner privilege */
403 403 (void) __priv_bracket(PRIV_ON);
404 404
405 405 procfd = open(pname, O_RDONLY);
406 406
407 407 /* drop proc_owner privilege after open */
408 408 (void) __priv_bracket(PRIV_OFF);
409 409
410 410 if (procfd < 0)
411 411 continue;
412 412
413 413 if (read(procfd, actinfo, sizeof (actinfo))
414 414 != sizeof (actinfo)) {
415 415 int err = errno;
416 416 (void) close(procfd);
417 417 if (err == EAGAIN)
418 418 goto retry;
419 419 if (err != ENOENT)
420 420 (void) fprintf(stderr, gettext(
421 421 "%s: read() failed on %s: %s \n"),
422 422 prog, pname, strerror(err));
423 423 continue;
424 424 }
425 425 (void) close(procfd);
426 426
427 427 up->p_igintr =
428 428 actinfo[SIGINT-1].sa_handler == SIG_IGN &&
429 429 actinfo[SIGQUIT-1].sa_handler == SIG_IGN;
430 430
431 431 /*
432 432 * Process args.
433 433 */
434 434 up->p_args[0] = 0;
435 435 clnarglist(info.pr_psargs);
436 436 (void) strcat(up->p_args, info.pr_psargs);
437 437 if (up->p_args[0] == 0 ||
438 438 up->p_args[0] == '-' && up->p_args[1] <= ' ' ||
439 439 up->p_args[0] == '?') {
440 440 (void) strcat(up->p_args, " (");
441 441 (void) strcat(up->p_args, up->p_comm);
442 442 (void) strcat(up->p_args, ")");
443 443 }
444 444 }
445 445
446 446 /*
447 447 * link pgrp together in case parents go away
448 448 * Pgrp chain is a single linked list originating
449 449 * from the pgrp leader to its group member.
450 450 */
451 451 if (info.pr_pgid != info.pr_pid) { /* not pgrp leader */
452 452 pgrp = findhash(info.pr_pgid);
453 453 up->p_pgrpl = pgrp->p_pgrpl;
454 454 pgrp->p_pgrpl = up;
455 455 }
456 456 parent = findhash(info.pr_ppid);
457 457
458 458 /* if this is the new member, link it in */
459 459 if (parent->p_upid != INITPROCESS) {
460 460 if (parent->p_child) {
461 461 up->p_sibling = parent->p_child;
462 462 up->p_child = 0;
463 463 }
464 464 parent->p_child = up;
465 465 }
466 466 }
467 467
468 468 /* revert to non-privileged user after opening */
469 469 (void) __priv_relinquish();
470 470
471 471 (void) closedir(dirp);
472 472 (void) time(&now); /* get current time */
473 473
474 474 /*
475 475 * loop through utmpx file, printing process info
476 476 * about each logged in user
477 477 */
478 478 for (ut = utmpbegin; ut < utmpend; ut++) {
479 479 if (ut->ut_type != USER_PROCESS)
480 480 continue;
481 481 if (sel_user && strncmp(ut->ut_name, sel_user, NMAX) != 0)
482 482 continue; /* we're looking for somebody else */
483 483
484 484 /* print login name of the user */
485 485 PRINTF(("%-*.*s ", LOGIN_WIDTH, NMAX, ut->ut_name));
486 486
487 487 /* print tty user is on */
488 488 if (lflag) {
489 489 PRINTF(("%-*.*s ", LINE_WIDTH, LMAX, ut->ut_line));
490 490 } else {
491 491 if (ut->ut_line[0] == 'p' && ut->ut_line[1] == 't' &&
492 492 ut->ut_line[2] == 's' && ut->ut_line[3] == '/') {
493 493 PRINTF(("%-*.*s ", LINE_WIDTH, LMAX,
494 494 &ut->ut_line[4]));
495 495 } else {
496 496 PRINTF(("%-*.*s ", LINE_WIDTH, LMAX,
497 497 ut->ut_line));
498 498 }
499 499 }
500 500
501 501 /* print when the user logged in */
502 502 if (lflag) {
503 503 time_t tim = ut->ut_xtime;
504 504 prtat(&tim);
505 505 }
506 506
507 507 /* print idle time */
508 508 idle = findidle(ut->ut_line);
509 509 prttime(idle, 8);
510 510 showtotals(findhash(ut->ut_pid));
511 511 }
512 512 if (fclose(stdout) == EOF) {
513 513 perror((gettext("%s: fclose failed"), prog));
514 514 exit(1);
515 515 }
516 516 return (0);
517 517 }
518 518
519 519 /*
520 520 * Prints the CPU time for all processes & children,
521 521 * and the cpu time for interesting process,
522 522 * and what the user is doing.
523 523 */
524 524 static void
525 525 showtotals(struct uproc *up)
526 526 {
527 527 jobtime = 0;
528 528 proctime = 0;
529 529 empty = 1;
530 530 curpid = -1;
531 531 add_times = 1;
532 532
533 533 calctotals(up);
534 534
535 535 if (lflag) {
536 536 /* print CPU time for all processes & children */
537 537 /* and need to convert clock ticks to seconds first */
538 538 prttime((time_t)jobtime, 8);
539 539
540 540 /* print cpu time for interesting process */
541 541 /* and need to convert clock ticks to seconds first */
542 542 prttime((time_t)proctime, 8);
543 543 }
544 544 /* what user is doing, current process */
545 545 PRINTF(("%-.32s\n", doing));
546 546 }
547 547
548 548 /*
549 549 * This recursive routine descends the process
550 550 * tree starting from the given process pointer(up).
551 551 * It used depth-first search strategy and also marked
552 552 * each node as visited as it traversed down the tree.
553 553 * It calculates the process time for all processes &
554 554 * children. It also finds the interesting process
555 555 * and determines its cpu time and command.
556 556 */
557 557 static void
558 558 calctotals(struct uproc *up)
559 559 {
560 560 struct uproc *zp;
561 561
562 562 /*
563 563 * Once a node has been visited, stop adding cpu times
564 564 * for its children so they don't get totalled twice.
565 565 * Still look for the interesting job for this utmp
566 566 * entry, however.
567 567 */
568 568 if (up->p_state == VISITED)
569 569 add_times = 0;
570 570 up->p_state = VISITED;
571 571 if (up->p_state == NONE || up->p_state == ZOMBIE)
572 572 return;
573 573
574 574 if (empty && !up->p_igintr) {
575 575 empty = 0;
576 576 curpid = -1;
577 577 }
578 578
579 579 if (up->p_upid > curpid && (!up->p_igintr || empty)) {
580 580 curpid = up->p_upid;
581 581 if (lflag)
582 582 (void) strcpy(doing, up->p_args);
583 583 else
584 584 (void) strcpy(doing, up->p_comm);
585 585 }
586 586
587 587 if (add_times == 1) {
588 588 jobtime += up->p_time + up->p_ctime;
589 589 proctime += up->p_time;
590 590 }
591 591
592 592 /* descend for its children */
593 593 if (up->p_child) {
594 594 calctotals(up->p_child);
595 595 for (zp = up->p_child->p_sibling; zp; zp = zp->p_sibling)
596 596 calctotals(zp);
597 597 }
598 598 }
599 599
600 600 /*
601 601 * Findhash finds the appropriate entry in the process
602 602 * hash table (pr_htbl) for the given pid in case that
603 603 * pid exists on the hash chain. It returns back a pointer
604 604 * to that uproc structure. If this is a new pid, it allocates
605 605 * a new node, initializes it, links it into the chain (after
606 606 * head) and returns a structure pointer.
607 607 */
608 608 static struct uproc *
609 609 findhash(pid_t pid)
610 610 {
611 611 struct uproc *up, *tp;
612 612
613 613 tp = up = &pr_htbl[pid % HSIZE];
614 614 if (up->p_upid == 0) { /* empty slot */
615 615 up->p_upid = pid;
616 616 up->p_state = NONE;
617 617 up->p_child = up->p_sibling = up->p_pgrpl = up->p_link = 0;
618 618 return (up);
619 619 }
620 620 if (up->p_upid == pid) { /* found in hash table */
621 621 return (up);
622 622 }
623 623 for (tp = up->p_link; tp; tp = tp->p_link) { /* follow chain */
624 624 if (tp->p_upid == pid)
625 625 return (tp);
626 626 }
627 627 tp = malloc(sizeof (*tp)); /* add new node */
628 628 if (!tp) {
629 629 (void) fprintf(stderr, gettext("%s: out of memory!: %s\n"),
630 630 prog, strerror(errno));
631 631 exit(1);
632 632 }
633 633 (void) memset(tp, 0, sizeof (*tp));
634 634 tp->p_upid = pid;
635 635 tp->p_state = NONE;
636 636 tp->p_child = tp->p_sibling = tp->p_pgrpl = 0;
637 637 tp->p_link = up->p_link; /* insert after head */
638 638 up->p_link = tp;
639 639 return (tp);
640 640 }
641 641
642 642 #define HR (60 * 60)
643 643 #define DAY (24 * HR)
644 644 #define MON (30 * DAY)
645 645
646 646 /*
647 647 * Prttime prints an elapsed time in hours, minutes, or seconds,
648 648 * right-justified with the rightmost column always blank.
649 649 * The second argument is the minimum field width.
650 650 */
651 651 static void
652 652 prttime(time_t tim, int width)
653 653 {
654 654 char value[36];
655 655
656 656 if (tim >= 36 * 60) {
657 657 (void) snprintf(value, sizeof (value), "%d:%02d:%02d",
658 658 (int)tim / HR, (int)(tim % HR) / 60, (int)tim % 60);
659 659 } else if (tim >= 60) {
660 660 (void) snprintf(value, sizeof (value), "%d:%02d",
661 661 (int)tim / 60, (int)tim % 60);
662 662 } else if (tim > 0) {
663 663 (void) snprintf(value, sizeof (value), "%d", (int)tim);
664 664 } else {
665 665 (void) strcpy(value, "0");
666 666 }
667 667 width = (width > 2) ? width - 1 : 1;
668 668 PRINTF(("%*s ", width, value));
669 669 }
670 670
671 671 /*
672 672 * Prints the ISO date or time given a pointer to a time of day,
673 673 * left-justfied in a 12-character expanding field with the
674 674 * rightmost column always blank.
675 675 * Includes a dcgettext() override in case a message catalog is needed.
676 676 */
677 677 static void
678 678 prtat(time_t *time)
679 679 {
680 680 struct tm *p;
681 681
682 682 p = localtime(time);
683 683 if (now - *time <= 18 * HR) {
684 684 char timestr[50];
685 685
686 686 (void) strftime(timestr, sizeof (timestr),
687 687 dcgettext(NULL, "%T", LC_TIME), p);
688 688 PRINTF(("%-11s ", timestr));
689 689 } else if (now - *time <= 7 * DAY) {
690 690 char weekdaytime[20];
691 691
692 692 (void) strftime(weekdaytime, sizeof (weekdaytime),
693 693 dcgettext(NULL, "%a %H:%M", LC_TIME), p);
694 694 PRINTF(("%-11s ", weekdaytime));
695 695 } else {
696 696 char monthtime[20];
697 697
698 698 (void) strftime(monthtime, sizeof (monthtime),
699 699 dcgettext(NULL, "%F", LC_TIME), p);
700 700 PRINTF(("%-11s ", monthtime));
701 701 }
702 702 }
703 703
704 704 /*
705 705 * find & return number of minutes current tty has been idle
706 706 */
707 707 static time_t
708 708 findidle(char *devname)
709 709 {
710 710 struct stat stbuf;
711 711 time_t lastaction, diff;
712 712 char ttyname[64];
713 713
714 714 (void) strcpy(ttyname, "/dev/");
715 715 (void) strcat(ttyname, devname);
716 716 if (stat(ttyname, &stbuf) != -1) {
717 717 lastaction = stbuf.st_atime;
718 718 diff = now - lastaction;
719 719 diff = DIV60(diff);
720 720 if (diff < 0)
721 721 diff = 0;
722 722 } else
723 723 diff = 0;
724 724 return (diff);
725 725 }
726 726
727 727 /*
728 728 * given a pointer to the argument string get rid of unsavory characters.
729 729 */
730 730 static void
731 731 clnarglist(char *arglist)
732 732 {
733 733 char *c;
734 734 int err = 0;
735 735
736 736 /* get rid of unsavory characters */
737 737 for (c = arglist; *c != NULL; c++) {
738 738 if ((*c < ' ') || (*c > 0176)) {
739 739 if (err++ > 5) {
740 740 *arglist = NULL;
741 741 break;
742 742 }
743 743 *c = '?';
744 744 }
745 745 }
746 746 }
↓ open down ↓ |
469 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX