Bug Summary

File:obj-scan-build/libps/../../libps/spec.c
Location:line 418, column 5
Description:Value stored to 'value_len' is never read

Annotated Source Code

1/* Access, formatting, & comparison routines for printing process info.
2
3 Copyright (C) 1995,96,97,99,2001,02 Free Software Foundation, Inc.
4
5 Written by Miles Bader <miles@gnu.org>
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2, or (at
10 your option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21#include <hurd.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <assert.h>
25#include <pwd.h>
26#include <hurd/resource.h>
27#include <unistd.h>
28#include <string.h>
29#include <timefmt.h>
30#include <sys/time.h>
31
32#include "ps.h"
33#include "common.h"
34
35/* XXX */
36static char *get_syscall_name (int num) { return 0; }
37static char *get_rpc_name (mach_msg_id_t it) { return 0; }
38
39/* ---------------------------------------------------------------- */
40/* Getter definitions */
41
42typedef void (*vf)();
43
44static int
45ps_get_pid (struct proc_stat *ps)
46{
47 return proc_stat_pid (ps)((ps)->pid);
48}
49const struct ps_getter ps_pid_getter =
50{"pid", PSTAT_PID0x00001, (vf) ps_get_pid};
51
52static int
53ps_get_thread_index (struct proc_stat *ps)
54{
55 return proc_stat_thread_index (ps)((ps)->thread_index);
56}
57const struct ps_getter ps_thread_index_getter =
58{"thread_index", PSTAT_THREAD0x00002, (vf) ps_get_thread_index};
59
60static struct ps_user *
61ps_get_owner (struct proc_stat *ps)
62{
63 return proc_stat_owner (ps)((ps)->owner);
64}
65const struct ps_getter ps_owner_getter =
66{"owner", PSTAT_OWNER0x100000, (vf) ps_get_owner};
67
68static int
69ps_get_owner_uid (struct proc_stat *ps)
70{
71 return proc_stat_owner_uid (ps)((ps)->owner_uid);
72}
73const struct ps_getter ps_owner_uid_getter =
74{"uid", PSTAT_OWNER_UID0x200000, (vf) ps_get_owner_uid};
75
76static int
77ps_get_ppid (struct proc_stat *ps)
78{
79 return proc_stat_proc_info (ps)((ps)->proc_info)->ppid;
80}
81const struct ps_getter ps_ppid_getter =
82{"ppid", PSTAT_PROC_INFO0x00020, (vf) ps_get_ppid};
83
84static int
85ps_get_pgrp (struct proc_stat *ps)
86{
87 return proc_stat_proc_info (ps)((ps)->proc_info)->pgrp;
88}
89const struct ps_getter ps_pgrp_getter =
90{"pgrp", PSTAT_PROC_INFO0x00020, (vf) ps_get_pgrp};
91
92static int
93ps_get_session (struct proc_stat *ps)
94{
95 return proc_stat_proc_info (ps)((ps)->proc_info)->session;
96}
97const struct ps_getter ps_session_getter =
98{"session", PSTAT_PROC_INFO0x00020, (vf) ps_get_session};
99
100static int
101ps_get_login_col (struct proc_stat *ps)
102{
103 return proc_stat_proc_info (ps)((ps)->proc_info)->logincollection;
104}
105const struct ps_getter ps_login_col_getter =
106{"login_col", PSTAT_PROC_INFO0x00020, (vf) ps_get_login_col};
107
108static int
109ps_get_num_threads (struct proc_stat *ps)
110{
111 return proc_stat_num_threads (ps)((ps)->num_threads);
112}
113const struct ps_getter ps_num_threads_getter =
114{"num_threads", PSTAT_NUM_THREADS0x00100, (vf)ps_get_num_threads};
115
116static void
117ps_get_args (struct proc_stat *ps, char **args_p, int *args_len_p)
118{
119 *args_p = proc_stat_args (ps)((ps)->args);
120 *args_len_p = proc_stat_args_len (ps)((ps)->args_len);
121}
122const struct ps_getter ps_args_getter =
123{"args", PSTAT_ARGS0x02000, ps_get_args};
124
125static void
126ps_get_env (struct proc_stat *ps, char **env_p, int *env_len_p)
127{
128 *env_p = proc_stat_env (ps)((ps)->env);
129 *env_len_p = proc_stat_env_len (ps)((ps)->env_len);
130}
131const struct ps_getter ps_env_getter =
132{"env", PSTAT_ENV0x2000000, ps_get_env};
133
134static int
135ps_get_state (struct proc_stat *ps)
136{
137 return proc_stat_state (ps)((ps)->state);
138}
139const struct ps_getter ps_state_getter =
140{"state", PSTAT_STATE0x04000, (vf) ps_get_state};
141
142static void
143ps_get_wait (struct proc_stat *ps, char **wait, int *rpc)
144{
145 *wait = ps->thread_wait;
146 *rpc = ps->thread_rpc;
147}
148const struct ps_getter ps_wait_getter =
149{"wait", PSTAT_THREAD_WAIT0x00800, ps_get_wait};
150
151static size_t
152ps_get_vsize (struct proc_stat *ps)
153{
154 return proc_stat_task_basic_info (ps)((ps)->task_basic_info)->virtual_size;
155}
156const struct ps_getter ps_vsize_getter =
157{"vsize", PSTAT_TASK_BASIC0x00040, (vf) ps_get_vsize};
158
159static size_t
160ps_get_rsize (struct proc_stat *ps)
161{
162 return proc_stat_task_basic_info (ps)((ps)->task_basic_info)->resident_size;
163}
164const struct ps_getter ps_rsize_getter =
165{"rsize", PSTAT_TASK_BASIC0x00040, (vf) ps_get_rsize};
166
167static int
168ps_get_cur_priority (struct proc_stat *ps)
169{
170 return proc_stat_thread_basic_info (ps)((ps)->thread_basic_info)->cur_priority;
171}
172const struct ps_getter ps_cur_priority_getter =
173{"cur_priority", PSTAT_THREAD_BASIC0x00200, (vf) ps_get_cur_priority};
174
175static int
176ps_get_base_priority (struct proc_stat *ps)
177{
178 return proc_stat_thread_basic_info (ps)((ps)->thread_basic_info)->base_priority;
179}
180const struct ps_getter ps_base_priority_getter =
181{"base_priority", PSTAT_THREAD_BASIC0x00200, (vf) ps_get_base_priority};
182
183static int
184ps_get_max_priority (struct proc_stat *ps)
185{
186 return proc_stat_thread_sched_info (ps)((ps)->thread_sched_info)->max_priority;
187}
188const struct ps_getter ps_max_priority_getter =
189{"max_priority", PSTAT_THREAD_SCHED0x00400, (vf) ps_get_max_priority};
190
191static void
192ps_get_usr_time (struct proc_stat *ps, struct timeval *tv)
193{
194 time_value_t tvt = proc_stat_thread_basic_info (ps)((ps)->thread_basic_info)->user_time;
195 tv->tv_sec = tvt.seconds;
196 tv->tv_usec = tvt.microseconds;
197}
198const struct ps_getter ps_usr_time_getter =
199{"usr_time", PSTAT_THREAD_BASIC0x00200, ps_get_usr_time};
200
201static void
202ps_get_sys_time (struct proc_stat *ps, struct timeval *tv)
203{
204 time_value_t tvt = proc_stat_thread_basic_info (ps)((ps)->thread_basic_info)->system_time;
205 tv->tv_sec = tvt.seconds;
206 tv->tv_usec = tvt.microseconds;
207}
208const struct ps_getter ps_sys_time_getter =
209{"sys_time", PSTAT_THREAD_BASIC0x00200, ps_get_sys_time};
210
211static void
212ps_get_tot_time (struct proc_stat *ps, struct timeval *tv)
213{
214 time_value_t tvt = proc_stat_thread_basic_info (ps)((ps)->thread_basic_info)->user_time;
215 time_value_add (&tvt, &proc_stat_thread_basic_info (ps)->system_time){ (&tvt)->microseconds += (&((ps)->thread_basic_info
)->system_time)->microseconds; (&tvt)->seconds +=
(&((ps)->thread_basic_info)->system_time)->seconds
; if ((&tvt)->microseconds >= (1000000)) { (&tvt
)->microseconds -= (1000000); (&tvt)->seconds++; } }
;
216 tv->tv_sec = tvt.seconds;
217 tv->tv_usec = tvt.microseconds;
218}
219const struct ps_getter ps_tot_time_getter =
220{"tot_time", PSTAT_THREAD_BASIC0x00200, ps_get_tot_time};
221
222static void
223ps_get_start_time (struct proc_stat *ps, struct timeval *tv)
224{
225 time_value_t *const tvt = &proc_stat_task_basic_info (ps)((ps)->task_basic_info)->creation_time;
226 tv->tv_sec = tvt->seconds;
227 tv->tv_usec = tvt->microseconds;
228}
229const struct ps_getter ps_start_time_getter =
230{"start_time", PSTAT_TASK_BASIC0x00040, ps_get_start_time};
231
232static float
233ps_get_rmem_frac (struct proc_stat *ps)
234{
235 static size_t mem_size = 0;
236
237 if (mem_size == 0)
238 {
239 host_basic_info_t info;
240 error_t err = ps_host_basic_info (&info);
241 if (err == 0)
242 mem_size = info->memory_size;
243 }
244
245 if (mem_size > 0)
246 return
247 (float)proc_stat_task_basic_info (ps)((ps)->task_basic_info)->resident_size
248 / (float)mem_size;
249 else
250 return 0.0;
251}
252const struct ps_getter ps_rmem_frac_getter =
253{"rmem_frac", PSTAT_TASK_BASIC0x00040, (vf) ps_get_rmem_frac};
254
255static float
256ps_get_cpu_frac (struct proc_stat *ps)
257{
258 return (float) proc_stat_thread_basic_info (ps)((ps)->thread_basic_info)->cpu_usage
259 / (float) TH_USAGE_SCALE1000;
260}
261const struct ps_getter ps_cpu_frac_getter =
262{"cpu_frac", PSTAT_THREAD_BASIC0x00200, (vf) ps_get_cpu_frac};
263
264static int
265ps_get_sleep (struct proc_stat *ps)
266{
267 return proc_stat_thread_basic_info (ps)((ps)->thread_basic_info)->sleep_time;
268}
269const struct ps_getter ps_sleep_getter =
270{"sleep", PSTAT_THREAD_BASIC0x00200, (vf) ps_get_sleep};
271
272static int
273ps_get_susp_count (struct proc_stat *ps)
274{
275 return proc_stat_suspend_count (ps)((ps)->suspend_count);
276}
277const struct ps_getter ps_susp_count_getter =
278{"susp_count", PSTAT_SUSPEND_COUNT0x08000, (vf) ps_get_susp_count};
279
280static int
281ps_get_proc_susp_count (struct proc_stat *ps)
282{
283 return proc_stat_task_basic_info (ps)((ps)->task_basic_info)->suspend_count;
284}
285const struct ps_getter ps_proc_susp_count_getter =
286{"proc_susp_count", PSTAT_TASK_BASIC0x00040, (vf) ps_get_proc_susp_count};
287
288static int
289ps_get_thread_susp_count (struct proc_stat *ps)
290{
291 return proc_stat_thread_basic_info (ps)((ps)->thread_basic_info)->suspend_count;
292}
293const struct ps_getter ps_thread_susp_count_getter =
294{"thread_susp_count", PSTAT_SUSPEND_COUNT0x08000, (vf) ps_get_thread_susp_count};
295
296static struct ps_tty *
297ps_get_tty (struct proc_stat *ps)
298{
299 return proc_stat_tty (ps)((ps)->tty);
300}
301const struct ps_getter ps_tty_getter =
302{"tty", PSTAT_TTY0x80000, (vf)ps_get_tty};
303
304static int
305ps_get_page_faults (struct proc_stat *ps)
306{
307 return proc_stat_task_events_info (ps)((ps)->task_events_info)->faults;
308}
309const struct ps_getter ps_page_faults_getter =
310{"page_faults", PSTAT_TASK_EVENTS0x00080, (vf) ps_get_page_faults};
311
312static int
313ps_get_cow_faults (struct proc_stat *ps)
314{
315 return proc_stat_task_events_info (ps)((ps)->task_events_info)->cow_faults;
316}
317const struct ps_getter ps_cow_faults_getter =
318{"cow_faults", PSTAT_TASK_EVENTS0x00080, (vf) ps_get_cow_faults};
319
320static int
321ps_get_pageins (struct proc_stat *ps)
322{
323 return proc_stat_task_events_info (ps)((ps)->task_events_info)->pageins;
324}
325const struct ps_getter ps_pageins_getter =
326{"pageins", PSTAT_TASK_EVENTS0x00080, (vf) ps_get_pageins};
327
328static int
329ps_get_msgs_sent (struct proc_stat *ps)
330{
331 return proc_stat_task_events_info (ps)((ps)->task_events_info)->messages_sent;
332}
333const struct ps_getter ps_msgs_sent_getter =
334{"msgs_sent", PSTAT_TASK_EVENTS0x00080, (vf) ps_get_msgs_sent};
335
336static int
337ps_get_msgs_rcvd (struct proc_stat *ps)
338{
339 return proc_stat_task_events_info (ps)((ps)->task_events_info)->messages_received;
340}
341const struct ps_getter ps_msgs_rcvd_getter =
342{"msgs_rcvd", PSTAT_TASK_EVENTS0x00080, (vf) ps_get_msgs_rcvd};
343
344static int
345ps_get_zero_fills (struct proc_stat *ps)
346{
347 return proc_stat_task_events_info (ps)((ps)->task_events_info)->zero_fills;
348}
349const struct ps_getter ps_zero_fills_getter =
350{"zero_fills", PSTAT_TASK_EVENTS0x00080, (vf) ps_get_zero_fills};
351
352static int
353ps_get_num_ports (struct proc_stat *ps)
354{
355 return proc_stat_num_ports (ps)((ps)->num_ports);
356}
357const struct ps_getter ps_num_ports_getter =
358{"num_ports", PSTAT_NUM_PORTS0x4000000, (vf) ps_get_num_ports};
359
360/* ---------------------------------------------------------------- */
361/* some printing functions */
362
363/* G () is a helpful macro that just returns the getter G's access function
364 cast into a function pointer returning TYPE, as how the function should be
365 called varies depending on the getter. */
366#define G(getter,type)((type (*)())((getter)->fn)) ((type (*)())((getter)->fn))
367
368/* Similar to G, but takes a fmt field and uses its getter. */
369#define FG(field,type)((type (*)())((field->spec->getter)->fn)) G(field->spec->getter, type)((type (*)())((field->spec->getter)->fn))
370
371error_t
372ps_emit_int (struct proc_stat *ps, struct ps_fmt_field *field,
373 struct ps_stream *stream)
374{
375 return ps_stream_write_int_field (stream, FG (field, int)((int (*)())((field->spec->getter)->fn))(ps), field->width);
376}
377
378error_t
379ps_emit_nz_int (struct proc_stat *ps, struct ps_fmt_field *field,
380 struct ps_stream *stream)
381{
382 int value = FG (field, int)((int (*)())((field->spec->getter)->fn))(ps);
383 if (value)
384 return ps_stream_write_int_field (stream, value, field->width);
385 else
386 return ps_stream_write_field (stream, "-", field->width);
387}
388
389error_t
390ps_emit_priority (struct proc_stat *ps, struct ps_fmt_field *field,
391 struct ps_stream *stream)
392{
393 return
394 ps_stream_write_int_field (stream,
395 MACH_PRIORITY_TO_NICE (FG (field, int)(ps))((((int (*)())((field->spec->getter)->fn))(ps)) - 25
)
,
396 field->width);
397}
398
399error_t
400ps_emit_num_blocks (struct proc_stat *ps, struct ps_fmt_field *field,
401 struct ps_stream *stream)
402{
403 char buf[20];
404 sprintf(buf, "%d", FG (field, int)((int (*)())((field->spec->getter)->fn))(ps) / 1024);
405 return ps_stream_write_field (stream, buf, field->width);
406}
407
408size_t
409sprint_frac_value (char *buf,
410 size_t value, int min_value_len,
411 size_t frac, int frac_scale,
412 int width)
413{
414 int value_len = 0;
415 int frac_len = 0;
416
417 if (value >= 1000) /* the integer part */
418 value_len = 4; /* values 1000-1023 */
Value stored to 'value_len' is never read
419 if (value >= 100)
420 value_len = 3;
421 else if (value >= 10)
422 value_len = 2;
423 else
424 value_len = 1;
425
426 while (value_len < min_value_len--)
427 *buf++ = '0';
428
429 for (frac_len = frac_scale
430 ; frac_len > 0 && (width < value_len + 1 + frac_len || frac % 10 == 0)
431 ; frac_len--)
432 frac /= 10;
433
434 if (frac_len > 0)
435 sprintf (buf, "%zd.%0*zd", value, frac_len, frac);
436 else
437 sprintf (buf, "%zd", value);
438
439 return strlen (buf);
440}
441
442error_t
443ps_emit_percent (struct proc_stat *ps, struct ps_fmt_field *field,
444 struct ps_stream *stream)
445{
446 char buf[20];
447 int width = field->width;
448 float perc = FG (field, float)((float (*)())((field->spec->getter)->fn))(ps) * 100;
449
450 if (width == 0)
451 sprintf (buf, "%g", perc);
452 else if (ABS (width)((width) < 0 ? -(width) : (width)) > 3)
453 sprintf(buf, "%.*f", ABS (width)((width) < 0 ? -(width) : (width)) - 3, perc);
454 else
455 sprintf (buf, "%d", (int) perc);
456
457 return ps_stream_write_field (stream, buf, width);
458}
459
460/* prints its value nicely */
461error_t
462ps_emit_nice_size_t (struct proc_stat *ps, struct ps_fmt_field *field,
463 struct ps_stream *stream)
464{
465 char buf[20];
466 size_t value = FG (field, size_t)((size_t (*)())((field->spec->getter)->fn))(ps);
467 char *sfx = " KMG";
468 size_t frac = 0;
469
470 while (value >= 1024)
471 {
472 frac = ((value & 0x3FF) * 1000) >> 10;
473 value >>= 10;
474 sfx++;
475 }
476
477 sprintf(buf
478 + sprint_frac_value (buf, value, 1, frac, 3, ABS (field->width)((field->width) < 0 ? -(field->width) : (field->width
))
- 1),
479 "%c", *sfx);
480
481 return ps_stream_write_field (stream, buf, field->width);
482}
483
484error_t
485ps_emit_seconds (struct proc_stat *ps, struct ps_fmt_field *field,
486 struct ps_stream *stream)
487{
488 char buf[20];
489 struct timeval tv;
490 int width = field->width, prec = field->precision;
491
492 FG (field, void)((void (*)())((field->spec->getter)->fn))(ps, &tv);
493
494 if ((field->flags & PS_FMT_FIELD_COLON_MOD0x2) && tv.tv_sec == 0)
495 strcpy (buf, "-");
496 else
497 fmt_seconds (&tv, !(field->flags & PS_FMT_FIELD_AT_MOD0x1), prec, ABS (width)((width) < 0 ? -(width) : (width)),
498 buf, sizeof (buf));
499
500 return ps_stream_write_field (stream, buf, width);
501}
502
503error_t
504ps_emit_minutes (struct proc_stat *ps, struct ps_fmt_field *field,
505 struct ps_stream *stream)
506{
507 char buf[20];
508 struct timeval tv;
509 int width = field->width;
510
511 FG (field, void)((void (*)())((field->spec->getter)->fn))(ps, &tv);
512
513 if ((field->flags & PS_FMT_FIELD_COLON_MOD0x2) && tv.tv_sec < 60)
514 strcpy (buf, "-");
515 else
516 fmt_minutes (&tv, !(field->flags & PS_FMT_FIELD_AT_MOD0x1), ABS (width)((width) < 0 ? -(width) : (width)),
517 buf, sizeof (buf));
518
519 return ps_stream_write_field (stream, buf, width);
520}
521
522error_t
523ps_emit_past_time (struct proc_stat *ps, struct ps_fmt_field *field,
524 struct ps_stream *stream)
525{
526 static struct timeval now;
527 char buf[20];
528 struct timeval tv;
529 int width = field->width;
530
531 FG (field, void)((void (*)())((field->spec->getter)->fn))(ps, &tv);
532
533 if (now.tv_sec == 0 && gettimeofday (&now, 0) < 0)
534 return errno(*__errno_location ());
535
536 fmt_past_time (&tv, &now, ABS (width)((width) < 0 ? -(width) : (width)), buf, sizeof buf);
537
538 return ps_stream_write_field (stream, buf, width);
539}
540
541error_t
542ps_emit_uid (struct proc_stat *ps, struct ps_fmt_field *field,
543 struct ps_stream *stream)
544{
545 int uid = FG (field, int)((int (*)())((field->spec->getter)->fn))(ps);
546 if (uid < 0)
547 return ps_stream_write_field (stream, "-", field->width);
548 else
549 return ps_stream_write_int_field (stream, uid, field->width);
550}
551
552error_t
553ps_emit_uname (struct proc_stat *ps, struct ps_fmt_field *field,
554 struct ps_stream *stream)
555{
556 int width = field->width;
557 struct ps_user *u = FG (field, struct ps_user *)((struct ps_user * (*)())((field->spec->getter)->fn)
)
(ps);
558 if (u)
559 {
560 struct passwd *pw = ps_user_passwd (u);
561 if (pw == NULL((void*)0))
562 return ps_stream_write_int_field (stream, ps_user_uid (u)((u)->uid), width);
563 else
564 return ps_stream_write_field (stream, pw->pw_name, width);
565 }
566 else
567 return ps_stream_write_field (stream, "-", width);
568}
569
570error_t
571ps_emit_user_name (struct proc_stat *ps, struct ps_fmt_field *field,
572 struct ps_stream *stream)
573{
574 int width = field->width;
575 struct ps_user *u = FG (field, struct ps_user *)((struct ps_user * (*)())((field->spec->getter)->fn)
)
(ps);
576 if (u)
577 {
578 struct passwd *pw = ps_user_passwd (u);
579 if (pw == NULL((void*)0))
580 {
581 char buf[20];
582 sprintf (buf, "(UID %d)", u->uid);
583 return ps_stream_write_field (stream, buf, width);
584 }
585 else
586 return ps_stream_write_field (stream, pw->pw_gecos, width);
587 }
588 else
589 return ps_stream_write_field (stream, "-", width);
590}
591
592/* prints a string with embedded nuls as spaces */
593error_t
594ps_emit_args (struct proc_stat *ps, struct ps_fmt_field *field,
595 struct ps_stream *stream)
596{
597 char *s0, *p, *q;
598 int s0len;
599 int width = field->width;
600 int fwidth = ABS (width)((width) < 0 ? -(width) : (width));
601 char static_buf[200];
602 char *buf = static_buf;
603
604 FG (field, void)((void (*)())((field->spec->getter)->fn))(ps, &s0, &s0len);
605
606 if (!s0 || s0len == 0 )
607 strcpy (buf, "-");
608 else
609 {
610 if (s0len > sizeof static_buf)
611 {
612 buf = malloc (s0len + 1);
613 if (buf == NULL((void*)0))
614 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
615 }
616
617 if (fwidth == 0 || fwidth > s0len)
618 fwidth = s0len;
619
620 for (p = buf, q = s0; fwidth-- > 0; p++, q++)
621 {
622 int ch = *q;
623 *p = (ch == '\0' ? ' ' : ch);
624 }
625 if (q > s0 && *(q - 1) == '\0')
626 *--p = '\0';
627 else
628 *p = '\0';
629 }
630
631 {
632 error_t err = ps_stream_write_trunc_field (stream, buf, width);
633 if (buf != static_buf)
634 free (buf);
635 return err;
636 }
637}
638
639error_t
640ps_emit_string (struct proc_stat *ps, struct ps_fmt_field *field,
641 struct ps_stream *stream)
642{
643 char *str;
644 int len;
645
646 FG (field, void)((void (*)())((field->spec->getter)->fn))(ps, &str, &len);
647
648 if (!str || len == 0)
649 str = "-";
650
651 return ps_stream_write_trunc_field (stream, str, field->width);
652}
653
654error_t
655ps_emit_tty_name (struct proc_stat *ps, struct ps_fmt_field *field,
656 struct ps_stream *stream)
657{
658 const char *name = "-";
659 struct ps_tty *tty = FG (field, struct ps_tty *)((struct ps_tty * (*)())((field->spec->getter)->fn))(ps);
660
661 if (tty)
662 {
663 name = ps_tty_short_name (tty);
664 if (name == NULL((void*)0) || *name == '\0')
665 name = "?";
666 }
667
668 return ps_stream_write_field (stream, name, field->width);
669}
670
671struct state_shadow
672{
673 /* If any states in STATES are set, the states in shadow are suppressed. */
674 int states;
675 int shadow;
676};
677
678static const struct state_shadow
679state_shadows[] = {
680 /* If the process has no parent, it's not a hurd process, and various hurd
681 process bits are likely to be noise, so turn them off (but leave the
682 noparent bit on). */
683 { PSTAT_STATE_P_NOPARENT0x08000, (PSTAT_STATE_P_ATTRS(0x00400 | 0x00800 | 0x01000 | 0x02000 | 0x04000 | 0x08000 | 0x10000
| 0x20000 | 0x40000 | 0x80000)
& ~PSTAT_STATE_P_NOPARENT0x08000) },
684 /* Don't show sleeping thread if one is running, or the process is stopped.*/
685 { PSTAT_STATE_T_RUN0x00004 | PSTAT_STATE_P_STOP0x00001,
686 PSTAT_STATE_T_SLEEP0x00020 | PSTAT_STATE_T_IDLE0x00040 | PSTAT_STATE_T_WAIT0x00010 },
687 /* Only show the longest sleep. */
688 { PSTAT_STATE_T_IDLE0x00040, PSTAT_STATE_T_SLEEP0x00020 | PSTAT_STATE_T_WAIT0x00010 },
689 { PSTAT_STATE_T_SLEEP0x00020, PSTAT_STATE_T_WAIT0x00010 },
690 /* Turn off the thread stop bits if any thread is not stopped. This is
691 generally reasonable, as threads are often suspended to be frobed; if
692 they're all suspended, then something's odd (probably in the debugger,
693 or crashed). */
694 { PSTAT_STATE_T_STATES(0x00004 | 0x00008 | 0x00010 | 0x00020 | 0x00040) & ~PSTAT_STATE_T_HALT0x00008,
695 PSTAT_STATE_T_HALT0x00008 | PSTAT_STATE_T_UNCLEAN0x00200 },
696 { 0 }
697};
698
699error_t
700ps_emit_state (struct proc_stat *ps, struct ps_fmt_field *field,
701 struct ps_stream *stream)
702{
703 char *tags;
704 int raw_state = FG (field, int)((int (*)())((field->spec->getter)->fn))(ps);
705 int state = raw_state;
706 char buf[20], *p = buf;
707 const struct state_shadow *shadow = state_shadows;
708
709 while (shadow->states)
710 {
711 if (raw_state & shadow->states)
712 state &= ~shadow->shadow;
713 shadow++;
714 }
715
716 for (tags = proc_stat_state_tags
717 ; state != 0 && *tags != '\0'
718 ; state >>= 1, tags++)
719 if (state & 1)
720 *p++ = *tags;
721
722 *p = '\0';
723
724 return ps_stream_write_field (stream, buf, field->width);
725}
726
727error_t
728ps_emit_wait (struct proc_stat *ps, struct ps_fmt_field *field,
729 struct ps_stream *stream)
730{
731 int rpc;
732 char *wait;
733 char buf[80];
734
735 FG (field, void)((void (*)())((field->spec->getter)->fn))(ps, &wait, &rpc);
736
737 if (wait == 0)
738 return ps_stream_write_field (stream, "?", field->width);
739 else if (*wait == 0)
740 return ps_stream_write_field (stream, "-", field->width);
741 else if (strcmp (wait, "kernel") == 0)
742 /* A syscall. RPC is actually the syscall number. */
743 {
744 char *name = get_syscall_name (rpc);
745 if (! name)
746 {
747 sprintf (buf, "syscall:%d", -rpc);
748 name = buf;
749 }
750 return ps_stream_write_field (stream, name, field->width);
751 }
752 else if (rpc)
753 /* An rpc (with msg id RPC); WAIT describes the dest port. */
754 {
755 char port_name_buf[20];
756 char *name = get_rpc_name (rpc);
757
758 /* See if we should give a more useful name for the port. */
759 if (strcmp (wait, "init#0") == 0)
760 wait = "cwd"; /* Current directory */
761 else if (strcmp (wait, "init#1") == 0)
762 wait = "root"; /* Root directory */
763 else if (strcmp (wait, "init#2") == 0)
764 wait = "auth"; /* Auth port */
765 else if (strcmp (wait, "init#3") == 0)
766 wait = "proc"; /* Proc port */
767 else if (strcmp (wait, "init#4") == 0)
768 wait = "cttyid"; /* Ctty id port */
769 else if (strcmp (wait, "init#5") == 0)
770 wait = "boot"; /* Bootstrap port */
771 else
772 /* See if we can shorten the name to fit better. */
773 {
774 char *abbrev = 0, *num = 0;
775 if (strncmp (wait, "fd#", 3) == 0)
776 abbrev = "fd", num = wait + 3;
777 else if (strncmp (wait, "bgfd#", 5) == 0)
778 abbrev = "bg", num = wait + 5;
779 else if (strncmp (wait, "port#", 5) == 0)
780 abbrev = "", num = wait + 5;
781 if (abbrev)
782 {
783 snprintf (port_name_buf, sizeof port_name_buf,
784 "%s%s", abbrev, num);
785 wait = port_name_buf;
786 }
787 }
788
789 if (name)
790 snprintf (buf, sizeof buf, "%s:%s", wait, name);
791 else
792 snprintf (buf, sizeof buf, "%s:%d", wait, rpc);
793
794 return ps_stream_write_field (stream, buf, field->width);
795 }
796 else
797 return ps_stream_write_field (stream, wait, field->width);
798}
799/* ---------------------------------------------------------------- */
800/* comparison functions */
801
802/* Evaluates CALL if both s1 & s2 are non-NULL, and otherwise returns -1, 0,
803 or 1 ala strcmp, considering NULL to be less than non-NULL. */
804#define GUARDED_CMP(s1, s2, call)((s1) == ((void*)0) ? (((s2) == ((void*)0)) ? 0 : -1) : ((s2)
== ((void*)0) ? 1 : (call)))
\
805 ((s1) == NULL((void*)0) ? (((s2) == NULL((void*)0)) ? 0 : -1) : ((s2) == NULL((void*)0) ? 1 : (call)))
806
807int
808ps_cmp_ints (struct proc_stat *ps1, struct proc_stat *ps2,
809 const struct ps_getter *getter)
810{
811 int (*gf)() = G (getter, int)((int (*)())((getter)->fn));
812 int v1 = gf(ps1), v2 = gf (ps2);
813 return v1 == v2 ? 0 : v1 < v2 ? -1 : 1;
814}
815
816int
817ps_cmp_floats (struct proc_stat *ps1, struct proc_stat *ps2,
818 const struct ps_getter *getter)
819{
820 float (*gf)() = G (getter, float)((float (*)())((getter)->fn));
821 float v1 = gf(ps1), v2 = gf (ps2);
822 return v1 == v2 ? 0 : v1 < v2 ? -1 : 1;
823}
824
825int
826ps_cmp_size_ts (struct proc_stat *ps1, struct proc_stat *ps2,
827 const struct ps_getter *getter)
828{
829 size_t (*gf)() = G (getter, size_t)((size_t (*)())((getter)->fn));
830 size_t v1 = gf(ps1), v2 = gf (ps2);
831 return v1 == v2 ? 0 : v1 < v2 ? -1 : 1;
832}
833
834int
835ps_cmp_uids (struct proc_stat *ps1, struct proc_stat *ps2,
836 const struct ps_getter *getter)
837{
838 struct ps_user *(*gf)() = G (getter, struct ps_user *)((struct ps_user * (*)())((getter)->fn));
839 struct ps_user *u1 = gf (ps1), *u2 = gf (ps2);
840 return (u1 ? ps_user_uid (u1)((u1)->uid) : -1) - (u2 ? ps_user_uid (u2)((u2)->uid) : -1);
841}
842
843int
844ps_cmp_unames (struct proc_stat *ps1, struct proc_stat *ps2,
845 const struct ps_getter *getter)
846{
847 struct ps_user *(*gf)() = G (getter, struct ps_user *)((struct ps_user * (*)())((getter)->fn));
848 struct ps_user *u1 = gf (ps1), *u2 = gf (ps2);
849 struct passwd *pw1 = u1 ? ps_user_passwd (u1) : 0;
850 struct passwd *pw2 = u2 ? ps_user_passwd (u2) : 0;
851 return GUARDED_CMP (pw1, pw2, strcmp (pw1->pw_name, pw2->pw_name))((pw1) == ((void*)0) ? (((pw2) == ((void*)0)) ? 0 : -1) : ((pw2
) == ((void*)0) ? 1 : (strcmp (pw1->pw_name, pw2->pw_name
))))
;
852}
853
854int
855ps_cmp_strings (struct proc_stat *ps1, struct proc_stat *ps2,
856 const struct ps_getter *getter)
857{
858 void (*gf)() = G (getter, void)((void (*)())((getter)->fn));
859 char *s1, *s2;
860 int s1len, s2len;
861
862 /* Get both strings */
863 gf (ps1, &s1, &s1len);
864 gf (ps2, &s2, &s2len);
865
866 return GUARDED_CMP(s1, s2, strncmp(s1, s2, MIN (s1len, s2len)))((s1) == ((void*)0) ? (((s2) == ((void*)0)) ? 0 : -1) : ((s2)
== ((void*)0) ? 1 : (strncmp(s1, s2, ((s1len) < (s2len) ?
(s1len) : (s2len))))))
;
867}
868
869int
870ps_cmp_times (struct proc_stat *ps1, struct proc_stat *ps2,
871 const struct ps_getter *getter)
872{
873 void (*g)() = G (getter, void)((void (*)())((getter)->fn));
874 struct timeval tv1, tv2;
875
876 g (ps1, &tv1);
877 g (ps2, &tv2);
878
879 return
880 tv1.tv_sec > tv2.tv_sec ? 1
881 : tv1.tv_sec < tv2.tv_sec ? -1
882 : tv1.tv_usec > tv2.tv_usec ? 1
883 : tv2.tv_usec < tv2.tv_usec ? -1
884 : 0;
885}
886
887/* ---------------------------------------------------------------- */
888/* `Nominal' functions -- return true for `unexciting' values. */
889
890/* For many things, zero is not so interesting. */
891int
892ps_nominal_zint (struct proc_stat *ps, const struct ps_getter *getter)
893{
894 return G (getter, int)((int (*)())((getter)->fn))(ps) == 0;
895}
896
897/* Neither is an empty string. */
898int
899ps_nominal_string (struct proc_stat *ps, const struct ps_getter *getter)
900{
901 char *str;
902 size_t len;
903 G (getter, char *)((char * (*)())((getter)->fn))(ps, &str, &len);
904 return !str || len == 0 || (len == 1 && *str == '-');
905}
906
907/* Priorities are similar, but have to be converted to the unix nice scale
908 first. */
909int
910ps_nominal_pri (struct proc_stat *ps, const struct ps_getter *getter)
911{
912 return MACH_PRIORITY_TO_NICE(G (getter, int)(ps))((((int (*)())((getter)->fn))(ps)) - 25) == 0;
913}
914
915/* Hurd processes usually have 2 threads; XXX is there someplace we get get
916 this number from? */
917int
918ps_nominal_nth (struct proc_stat *ps, const struct ps_getter *getter)
919{
920 return G (getter, int)((int (*)())((getter)->fn))(ps) == 2;
921}
922
923static int own_uid = -2; /* -1 means no uid at all. */
924
925/* A user is nominal if it's the current user. */
926int
927ps_nominal_user (struct proc_stat *ps, const struct ps_getter *getter)
928{
929 struct ps_user *u = G (getter, struct ps_user *)((struct ps_user * (*)())((getter)->fn))(ps);
930 if (own_uid == -2)
931 own_uid = getuid ();
932 return own_uid >= 0 && u && u->uid == own_uid;
933}
934
935/* A uid is nominal if it's that of the current user. */
936int
937ps_nominal_uid (struct proc_stat *ps, const struct ps_getter *getter)
938{
939 uid_t uid = G (getter, uid_t)((uid_t (*)())((getter)->fn))(ps);
940 if (own_uid == -2)
941 own_uid = getuid ();
942 return own_uid >= 0 && uid == own_uid;
943}
944
945/* ---------------------------------------------------------------- */
946
947/* Returns the first entry called NAME in the vector of fmt_specs SPECS. If
948 the result is in fact an alias entry, returns in ALIASED_TO the name of
949 the desired source. */
950static const struct ps_fmt_spec *
951specv_find (const struct ps_fmt_spec *specs, const char *name,
952 char **aliased_to)
953{
954 while (! ps_fmt_spec_is_end (specs)((specs)->name == ((void*)0)))
955 {
956 char *alias = index (specs->name, '=');
957 if (alias)
958 {
959 unsigned name_len = strlen (name);
960
961 if (name_len == alias - specs->name
962 && strncasecmp (name, specs->name, name_len) == 0)
963 /* SPECS is an alias, lookup what it refs to. */
964 {
965 *aliased_to = alias + 1;
966 return specs;
967 }
968 }
969 else
970 if (strcasecmp (specs->name, name) == 0)
971 return specs;
972 specs++;
973 }
974
975 return 0;
976}
977
978/* Number of specs allocated in each block of expansions. */
979#define EXP_BLOCK_SIZE20 20
980
981/* A node in a linked list of spec vectors. */
982struct ps_fmt_spec_block
983{
984 struct ps_fmt_spec_block *next;
985 struct ps_fmt_spec specs[EXP_BLOCK_SIZE20];
986};
987
988/* Adds a new alias expansion, using fields from ALIAS, where non-zero,
989 otherwise SRC, to SPECS. */
990struct ps_fmt_spec *
991specs_add_alias (struct ps_fmt_specs *specs,
992 const struct ps_fmt_spec *alias,
993 const struct ps_fmt_spec *src)
994{
995 struct ps_fmt_spec *exp;
996 struct ps_fmt_spec_block *block;
997 char *name_end = index (alias->name, '=');
998 size_t name_len = name_end ? name_end - alias->name : strlen (alias->name);
999
1000 for (block = specs->expansions; block; block = block->next)
1001 {
1002 exp = block->specs;
1003 while (! ps_fmt_spec_is_end (exp)((exp)->name == ((void*)0)))
1004 exp++;
1005 if (exp + 1 < block->specs + EXP_BLOCK_SIZE20)
1006 /* Found some empty space at EXP. */
1007 break;
1008 }
1009
1010 if (! block)
1011 /* Ran out of blocks, we gotta make a new one. */
1012 {
1013 block = malloc (sizeof (struct ps_fmt_spec_block));
1014 if (! block)
1015 return 0;
1016 block->next = specs->expansions;
1017 specs->expansions = block;
1018 exp = block->specs;
1019 }
1020
1021 /* EXP gets its name from ALIAS, but only the bit before the alias marker. */
1022 exp->name = malloc (name_len + 1);
1023 if (! exp->name)
1024 return 0;
1025 bcopy ((char *)alias->name, (char *)exp->name, name_len);
1026 ((char *)exp->name)[name_len] = '\0';
1027
1028 /* Copy the rest of the fields from ALIAS, but defaulting to SRC. */
1029 exp->title = alias->title ?: src->title;
1030 exp->width = alias->width ?: src->width;
1031 exp->precision = alias->precision >= 0 ? alias->precision : src->precision;
1032 exp->flags = src->flags ^ alias->flags;
1033 exp->getter = alias->getter ?: src->getter;
1034 exp->output_fn = alias->output_fn ?: src->output_fn;
1035 exp->cmp_fn = alias->cmp_fn ?: src->cmp_fn;
1036 exp->nominal_fn = alias->nominal_fn ?: src->nominal_fn;
1037
1038 /* Now add the list-end marker. */
1039 bzero (exp + 1, sizeof (*exp));
1040
1041 return exp;
1042}
1043
1044const struct ps_fmt_spec *
1045ps_fmt_specs_find (struct ps_fmt_specs *specs, const char *name)
1046{
1047 if (specs) /* Allow NULL to make recursion more handy. */
1048 {
1049 struct ps_fmt_spec_block *block;
1050 char *aliased_to = 0;
1051 const struct ps_fmt_spec *s = 0;
1052
1053 /* If SPECS contains any alias expansions, look there first. */
1054 for (block = specs->expansions; block && !s; block = block->next)
1055 s = specv_find (block->specs, name, &aliased_to);
1056
1057 if (! s)
1058 /* Look in the local list of specs. */
1059 s = specv_find (specs->specs, name, &aliased_to);
1060
1061 if (s)
1062 {
1063 if (aliased_to)
1064 {
1065 const struct ps_fmt_spec *src; /* What S is an alias to. */
1066
1067 if (strcasecmp (name, aliased_to) == 0)
1068 /* An alias to the same name (useful to just change some
1069 property) -- start looking up in the parent. */
1070 src = ps_fmt_specs_find (specs->parent, aliased_to);
1071 else
1072 src = ps_fmt_specs_find (specs, aliased_to);
1073
1074 if (! src)
1075 return 0;
1076
1077 s = specs_add_alias (specs, s, src);
1078 }
1079 }
1080 else
1081 /* Try again with our parent. */
1082 s = ps_fmt_specs_find (specs->parent, name);
1083
1084 return s;
1085 }
1086 else
1087 return 0;
1088}
1089
1090/* ---------------------------------------------------------------- */
1091
1092static const struct ps_fmt_spec specs[] =
1093{
1094 {"PID", 0, -5, -1, 0,
1095 &ps_pid_getter, ps_emit_int, ps_cmp_ints, 0},
1096 {"TH", "TH#", -2, -1, 0,
1097 &ps_thread_index_getter,ps_emit_int, ps_cmp_ints, 0},
1098 {"PPID", 0, -5, -1, 0,
1099 &ps_ppid_getter, ps_emit_int, ps_cmp_ints, 0},
1100 {"UID", 0, -4, -1, PS_FMT_FIELD_KEEP0x4,
1101 &ps_owner_uid_getter, ps_emit_uid, ps_cmp_ints, ps_nominal_uid},
1102 {"User", 0, 8, -1, PS_FMT_FIELD_KEEP0x4,
1103 &ps_owner_getter, ps_emit_uname, ps_cmp_unames, ps_nominal_user},
1104 {"NTh", 0, -2, -1, 0,
1105 &ps_num_threads_getter, ps_emit_int, ps_cmp_ints, ps_nominal_nth},
1106 {"PGrp", 0, -5, -1, 0,
1107 &ps_pgrp_getter, ps_emit_int, ps_cmp_ints, 0},
1108 {"Sess", 0, -5, -1, 0,
1109 &ps_session_getter, ps_emit_int, ps_cmp_ints, 0},
1110 {"LColl", 0, -5, -1, 0,
1111 &ps_login_col_getter, ps_emit_int, ps_cmp_ints, 0},
1112 {"Args", 0, 0, -1, 0,
1113 &ps_args_getter, ps_emit_args, ps_cmp_strings,ps_nominal_string},
1114 {"Arg0", 0, 0, -1, 0,
1115 &ps_args_getter, ps_emit_string, ps_cmp_strings,ps_nominal_string},
1116 {"Env", 0, 0, -1, 0,
1117 &ps_env_getter, ps_emit_args, ps_cmp_strings,ps_nominal_string},
1118 {"Start", 0, -7, 1, 0,
1119 &ps_start_time_getter, ps_emit_past_time, ps_cmp_times,0},
1120 {"Time", 0, -8, 2, 0,
1121 &ps_tot_time_getter, ps_emit_seconds, ps_cmp_times, 0},
1122 {"UTime", 0, -8, 2, 0,
1123 &ps_usr_time_getter, ps_emit_seconds, ps_cmp_times, 0},
1124 {"STime", 0, -8, 2, 0,
1125 &ps_sys_time_getter, ps_emit_seconds, ps_cmp_times, 0},
1126 {"VSize", 0, -5, -1, 0,
1127 &ps_vsize_getter, ps_emit_nice_size_t,ps_cmp_size_ts, 0},
1128 {"RSize", 0, -5, -1, 0,
1129 &ps_rsize_getter, ps_emit_nice_size_t,ps_cmp_size_ts, 0},
1130 {"Pri", 0, -3, -1, 0,
1131 &ps_cur_priority_getter,ps_emit_priority,ps_cmp_ints, ps_nominal_pri},
1132 {"BPri", 0, -3, -1, 0,
1133 &ps_base_priority_getter,ps_emit_priority,ps_cmp_ints, ps_nominal_pri},
1134 {"MPri", 0, -3, -1, 0,
1135 &ps_max_priority_getter,ps_emit_priority,ps_cmp_ints, ps_nominal_pri},
1136 {"Mem", "%Mem", -4, -1, 0,
1137 &ps_rmem_frac_getter, ps_emit_percent, ps_cmp_floats, 0},
1138 {"CPU", "%CPU", -4, -1, 0,
1139 &ps_cpu_frac_getter, ps_emit_percent, ps_cmp_floats, 0},
1140 {"State", 0, 4, -1, 0,
1141 &ps_state_getter, ps_emit_state, 0, 0},
1142 {"Wait", 0, 10, -1, 0,
1143 &ps_wait_getter, ps_emit_wait, 0, 0},
1144 {"Sleep", 0, -2, -1, 0,
1145 &ps_sleep_getter, ps_emit_int, ps_cmp_ints, ps_nominal_zint},
1146 {"Susp", 0, -2, -1, 0,
1147 &ps_susp_count_getter, ps_emit_int, ps_cmp_ints, ps_nominal_zint},
1148 {"PSusp", 0, -2, -1, 0,
1149 &ps_proc_susp_count_getter, ps_emit_int, ps_cmp_ints, ps_nominal_zint},
1150 {"TSusp", 0, -2, -1, 0,
1151 &ps_thread_susp_count_getter, ps_emit_int,ps_cmp_ints, ps_nominal_zint},
1152 {"TTY", 0, -2, -1, 0,
1153 &ps_tty_getter, ps_emit_tty_name,ps_cmp_strings,0},
1154 {"PgFlts", 0, -5, -1, 0,
1155 &ps_page_faults_getter, ps_emit_int, ps_cmp_ints, ps_nominal_zint},
1156 {"COWFlts", 0, -5, -1, 0,
1157 &ps_cow_faults_getter, ps_emit_int, ps_cmp_ints, ps_nominal_zint},
1158 {"PgIns", 0, -5, -1, 0,
1159 &ps_pageins_getter, ps_emit_int, ps_cmp_ints, ps_nominal_zint},
1160 {"MsgIn", 0, -5, -1, 0,
1161 &ps_msgs_rcvd_getter, ps_emit_int, ps_cmp_ints, ps_nominal_zint},
1162 {"MsgOut", 0, -5, -1, 0,
1163 &ps_msgs_sent_getter, ps_emit_int, ps_cmp_ints, ps_nominal_zint},
1164 {"ZFills", 0, -5, -1, 0,
1165 &ps_zero_fills_getter, ps_emit_int, ps_cmp_ints, ps_nominal_zint},
1166 {"Ports", 0, -5, -1, 0,
1167 &ps_num_ports_getter, ps_emit_int, ps_cmp_ints, 0},
1168 {0}
1169};
1170
1171struct ps_fmt_specs ps_std_fmt_specs = { specs, 0 };