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