output.c 89.3 KB
Newer Older
csmall's avatar
csmall committed
1
/*
2
3
 * output.c - ps output definitions
 * Copyright 1999-2004 by Albert Cahalan
csmall's avatar
csmall committed
4
 *
5
6
7
8
9
10
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
csmall's avatar
csmall committed
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
13
14
15
16
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
csmall's avatar
csmall committed
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 */

/*
 * This file is really gross, and I know it. I looked into several
 * alternate ways to deal with the mess, and they were all ugly.
 *
 * FreeBSD has a fancy hack using offsets into a struct -- that
 * saves code but it is _really_ gross. See the PO macro below.
 *
 * We could have a second column width for wide output format.
 * For example, Digital prints the real-time signals.
 */

/*
 * Data table idea:
 *
 * table 1 maps aix to specifier
 * table 2 maps shortsort to specifier
 * table 3 maps macro to specifiers
 * table 4 maps specifier to title,datatype,offset,vendor,helptext
 * table 5 maps datatype to justification,width,widewidth,sorting,printing
 *
 * Here, "datatype" could be user,uid,u16,pages,deltaT,signals,tty,longtty...
 * It must be enough to determine printing and sorting.
 *
 * After the tables, increase width as needed to fit the header.
 *
 * Table 5 could go in a file with the output functions.
 */
47

csmall's avatar
csmall committed
48
#include <ctype.h>
49
#if ENABLE_LIBSELINUX
50
#include <dlfcn.h>
51
#endif
csmall's avatar
csmall committed
52
53
54
55
56
57
58
#include <fcntl.h>
#include <grp.h>
#include <limits.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
59
60
61
#include <time.h>
#include <unistd.h>

csmall's avatar
csmall committed
62
#include <sys/ioctl.h>
63
#include <sys/mman.h>
csmall's avatar
csmall committed
64
65
66
67
68
#include <sys/resource.h>
#include <sys/types.h>

#include "../proc/readproc.h"
#include "../proc/sysinfo.h"
albert's avatar
albert committed
69
#include "../proc/wchan.h"
csmall's avatar
csmall committed
70
71
#include "../proc/procps.h"
#include "../proc/devname.h"
albert's avatar
albert committed
72
#include "../proc/escape.h"
73
#include "../proc/numa.h"
74

csmall's avatar
csmall committed
75
76
77
78
79
80
81
82
#include "common.h"

/* TODO:
 * Stop assuming system time is local time.
 */

#define COLWID 240 /* satisfy snprintf, which is faster than sprintf */

83
84
static unsigned max_rightward = OUTBUF_SIZE-1; /* space for RIGHT stuff */
static unsigned max_leftward = OUTBUF_SIZE-1; /* space for LEFT stuff */
csmall's avatar
csmall committed
85

albert's avatar
albert committed
86

csmall's avatar
csmall committed
87
88
89

static int wide_signals;  /* true if we have room */

90
static time_t seconds_since_1970;
csmall's avatar
csmall committed
91
92
93
94
95
96
97
98
99
100


/*************************************************************************/
/************ Lots of sort functions, starting with the NOP **************/

static int sr_nop(const proc_t* a, const proc_t* b){
  (void)a;(void)b; /* shut up gcc */
  return 0;
}

Craig Small's avatar
Craig Small committed
101
102
static int sr_cgroup(const proc_t* a, const proc_t* b)
{
Craig Small's avatar
Craig Small committed
103
104
105
106
107
108
    /* This is a "vector" of one */
    if (*a->cgroup == NULL || *b->cgroup == NULL)
        return 0;
    return strcmp(*a->cgroup, *b->cgroup);
}

csmall's avatar
csmall committed
109
110
111
112
113
114
115
116
117
118
119
120
#define CMP_STR(NAME) \
static int sr_ ## NAME(const proc_t* P, const proc_t* Q) { \
    return strcmp(P->NAME, Q->NAME); \
}

#define CMP_INT(NAME) \
static int sr_ ## NAME (const proc_t* P, const proc_t* Q) { \
    if (P->NAME < Q->NAME) return -1; \
    if (P->NAME > Q->NAME) return  1; \
    return 0; \
}

121
/* fast versions, for values which either:
albert's avatar
albert committed
122
123
124
125
126
127
128
 * a. differ by no more than 0x7fffffff
 * b. only need to be grouped same w/ same
 */
#define CMP_SMALL(NAME) \
static int sr_ ## NAME (const proc_t* P, const proc_t* Q) { \
    return (int)(P->NAME) - (int)(Q->NAME); \
}
129
130
131
132
#define CMP_SMALL2(NAME,WHAT) \
static int sr_ ## NAME (const proc_t* P, const proc_t* Q) { \
    return (int)(P->WHAT) - (int)(Q->WHAT); \
}
albert's avatar
albert committed
133

134
135
#define cook_time(P) (P->utime + P->stime) / Hertz

136
#define cook_etime(P) (((unsigned long long)seconds_since_boot >= (P->start_time / Hertz)) ? ((unsigned long long)seconds_since_boot - (P->start_time / Hertz)) : 0)
137
138
139
140
141
142
143
144
145
146
147

#define CMP_COOKED_TIME(NAME) \
static int sr_ ## NAME (const proc_t* P, const proc_t* Q) { \
    unsigned long p_time,q_time; \
    p_time=cook_ ##NAME (P); \
    q_time=cook_ ##NAME (Q); \
    if (p_time < q_time) return -1; \
    if (p_time > q_time) return 1; \
    return 0; \
}

148
149
#define CMP_NS(NAME, ID) \
static int sr_ ## NAME (const proc_t* P, const proc_t* Q) { \
150
151
    if ((unsigned long)P->ns[ID] < (unsigned long)Q->ns[ID]) return -1; \
    if ((unsigned long)P->ns[ID] > (unsigned long)Q->ns[ID]) return  1; \
152
153
154
    return 0; \
}

albert's avatar
albert committed
155
CMP_INT(rtprio)
albert's avatar
albert committed
156
CMP_SMALL(sched)
csmall's avatar
csmall committed
157
CMP_INT(cutime)
albert's avatar
albert committed
158
CMP_SMALL(priority)                                             /* nice */
albert's avatar
albert committed
159
CMP_SMALL(nlwp)
albert's avatar
albert committed
160
CMP_SMALL(nice)                                                 /* priority */
csmall's avatar
csmall committed
161
CMP_INT(rss)      /* resident set size from stat file */ /* vm_rss, resident */
162
CMP_INT(alarm)
csmall's avatar
csmall committed
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
CMP_INT(size)      /* total pages */                     /* vm_size, vsize */
CMP_INT(resident)  /* resident pages */                     /* vm_rss, rss */
CMP_INT(share)     /* shared pages */
CMP_INT(trs)       /* executable pages */
CMP_INT(lrs)       /* obsolete "library" pages above 0x60000000 */
CMP_INT(drs)       /* other pages (assumed data?) */
CMP_INT(dt)        /* dirty pages */

CMP_INT(vm_size)    /* kB VM */                             /* size, vsize */
CMP_INT(vm_lock)    /* kB locked */
CMP_INT(vm_rss)     /* kB rss */                          /* rss, resident */
CMP_INT(vm_data)    /* kB "data" == data-stack */
CMP_INT(vm_stack)   /* kB stack */
CMP_INT(vm_exe)     /* kB "exec" == exec-lib */
CMP_INT(vm_lib)     /* kB "libraries" */
CMP_INT(vsize)      /* pages VM */                        /* size, vm_size */
CMP_INT(rss_rlim)
albert's avatar
albert committed
180
CMP_SMALL(flags)
csmall's avatar
csmall committed
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
CMP_INT(min_flt)
CMP_INT(maj_flt)
CMP_INT(cmin_flt)
CMP_INT(cmaj_flt)
CMP_INT(utime)
CMP_INT(stime)    /* Old: sort by systime. New: show start time. Uh oh. */
CMP_INT(start_code)
CMP_INT(end_code)
CMP_INT(start_stack)
CMP_INT(kstk_esp)
CMP_INT(kstk_eip)
CMP_INT(start_time)
CMP_INT(wchan)

/* CMP_STR(*environ) */
/* CMP_STR(*cmdline) */

CMP_STR(ruser)
CMP_STR(euser)
CMP_STR(suser)
CMP_STR(fuser)
CMP_STR(rgroup)
CMP_STR(egroup)
CMP_STR(sgroup)
CMP_STR(fgroup)
CMP_STR(cmd)
/* CMP_STR(ttyc) */    /* FIXME -- use strncmp with 8 max */

CMP_INT(ruid)
CMP_INT(rgid)
CMP_INT(euid)
CMP_INT(egid)
CMP_INT(suid)
CMP_INT(sgid)
CMP_INT(fuid)
CMP_INT(fgid)
217
218
CMP_SMALL2(procs,tgid)
CMP_SMALL2(tasks,tid)
albert's avatar
albert committed
219
220
221
CMP_SMALL(ppid)
CMP_SMALL(pgrp)
CMP_SMALL(session)
csmall's avatar
csmall committed
222
CMP_INT(tty)
albert's avatar
albert committed
223
CMP_SMALL(tpgid)
csmall's avatar
csmall committed
224

albert's avatar
albert committed
225
CMP_SMALL(pcpu)
csmall's avatar
csmall committed
226

albert's avatar
albert committed
227
CMP_SMALL(state)
csmall's avatar
csmall committed
228

229
230
231
CMP_COOKED_TIME(time)
CMP_COOKED_TIME(etime)

232
233
234
235
236
237
238
CMP_NS(ipcns, IPCNS);
CMP_NS(mntns, MNTNS);
CMP_NS(netns, NETNS);
CMP_NS(pidns, PIDNS);
CMP_NS(userns, USERNS);
CMP_NS(utsns, UTSNS);

239
CMP_STR(lxcname)
240
CMP_STR(cgname)
241

242
243
244
245
246
247
248
249
250
251
/* approximation to: kB of address space that could end up in swap */
static int sr_swapable(const proc_t* P, const proc_t* Q) {
  unsigned long p_swapable = P->vm_data + P->vm_stack;
  unsigned long q_swapable = Q->vm_data + Q->vm_stack;
  if (p_swapable < q_swapable) return -1;
  if (p_swapable > q_swapable) return  1;
  return 0;
}


csmall's avatar
csmall committed
252
253
254
/***************************************************************************/
/************ Lots of format functions, starting with the NOP **************/

albert's avatar
albert committed
255
256
// so popular it can't be "static"
int pr_nop(char *restrict const outbuf, const proc_t *restrict const pp){
albert's avatar
albert committed
257
  (void)pp;
csmall's avatar
csmall committed
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
  return snprintf(outbuf, COLWID, "%c", '-');
}


/********* Unix 98 ************/

/***

Only comm and args are allowed to contain blank characters; all others are
not. Any implementation-dependent variables will be specified in the system
documentation along with the default header and indicating if the field
may contain blank characters.

Some headers do not have a standardized specifier!

%CPU	pcpu	The % of cpu time used recently, with unspecified "recently".
ADDR		The address of the process.
C		Processor utilisation for scheduling.
CMD		The command name, or everything with -f.
COMMAND	args	Command + args. May chop as desired. May use either version.
COMMAND	comm	argv[0]
ELAPSED	etime	Elapsed time since the process was started. [[dd-]hh:]mm:ss
F		Flags (octal and additive)
GROUP	group	Effective group ID, prefer text over decimal.
NI	nice	Decimal system scheduling priority, see nice(1).
PGID	pgid	The decimal value of the process group ID.
PID	pid	Decimal PID.
PPID	ppid	Decimal PID.
PRI		Priority. Higher numbers mean lower priority.
RGROUP	rgroup	Real group ID, prefer text over decimal.
RUSER	ruser	Real user ID, prefer text over decimal.
S		The state of the process.
STIME		Starting time of the process.
SZ		The size in blocks of the core image of the process.
TIME	time	Cumulative CPU time. [dd-]hh:mm:ss
TT	tty	Name of tty in format used by who(1).
TTY		The controlling terminal for the process.
UID		UID, or name when -f
USER	user	Effective user ID, prefer text over decimal.
VSZ	vsz	Virtual memory size in decimal kB.
WCHAN		Where waiting/sleeping or blank if running.

The nice value is used to compute the priority.

For some undefined ones, Digital does:

F       flag    Process flags -- but in hex!
PRI     pri     Process priority
S       state   Symbolic process status
TTY     tt,tty,tname,longtname  -- all do "ttyp1", "console", "??"
UID     uid     Process user ID (effective UID)
WCHAN   wchan   Address of event on which a

For some undefined ones, Sun does:

ADDR	addr	memory address of the process
C	c	Processor utilization  for  scheduling  (obsolete).
CMD
F	f
S	s	state: OSRZT
STIME		start time, printed w/o blanks. If 24h old, months & days
SZ		size (in pages) of the swappable process's image in main memory
TTY
UID	uid
WCHAN	wchan

For some undefined ones, SCO does:
ADDR	addr	Virtual address of the process' entry in the process table.
SZ		swappable size in kB of the virtual data and stack
STIME	stime	hms or md time format
***/

/* Source & destination are known. Return bytes or screen characters? */
331
332
333
334
335
336
337
//
//       OldLinux   FreeBSD    HPUX
// ' '    '    '     '  '      '  '
// 'L'    ' \_ '     '`-'      '  '
// '+'    ' \_ '     '|-'      '  '
// '|'    ' |  '     '| '      '  '
//
albert's avatar
albert committed
338
static int forest_helper(char *restrict const outbuf){
csmall's avatar
csmall committed
339
340
  char *p = forest_prefix;
  char *q = outbuf;
341
342
  int rightward = max_rightward < OUTBUF_SIZE ? max_rightward : OUTBUF_SIZE-1;
  *q = '\0';
csmall's avatar
csmall committed
343
344
345
346
  if(!*p) return 0;
  /* Arrrgh! somebody defined unix as 1 */
  if(forest_type == 'u') goto unixy;
  while(*p){
347
    if (rightward < 4) break;
csmall's avatar
csmall committed
348
349
350
351
352
353
354
355
    switch(*p){
    case ' ': strcpy(q, "    ");  break;
    case 'L': strcpy(q, " \\_ "); break;
    case '+': strcpy(q, " \\_ "); break;
    case '|': strcpy(q, " |  ");  break;
    case '\0': return q-outbuf;    /* redundant & not used */
    }
    q += 4;
albert's avatar
albert committed
356
    rightward -= 4;
csmall's avatar
csmall committed
357
358
359
360
361
    p++;
  }
  return q-outbuf;   /* gcc likes this here */
unixy:
  while(*p){
362
    if (rightward < 2) break;
csmall's avatar
csmall committed
363
364
365
366
367
368
369
370
    switch(*p){
    case ' ': strcpy(q, "  "); break;
    case 'L': strcpy(q, "  "); break;
    case '+': strcpy(q, "  "); break;
    case '|': strcpy(q, "  "); break;
    case '\0': return q-outbuf;    /* redundant & not used */
    }
    q += 2;
albert's avatar
albert committed
371
    rightward -= 2;
csmall's avatar
csmall committed
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
    p++;
  }
  return q-outbuf;   /* gcc likes this here */
}


/* XPG4-UNIX, according to Digital:
The "args" and "command" specifiers show what was passed to the command.
Modifications to the arguments are not shown.
*/

/*
 * pp->cmd       short accounting name (comm & ucomm)
 * pp->cmdline   long name with args (args & command)
 * pp->environ   environment
 */

albert's avatar
albert committed
389
390
// FIXME: some of these may hit the guard page in forest mode

391
392
393
#define OUTBUF_SIZE_AT(endp) \
  (((endp) >= outbuf && (endp) < outbuf + OUTBUF_SIZE) ? (outbuf + OUTBUF_SIZE) - (endp) : 0)

394
395
396
/*
 * "args", "cmd", "command" are all the same:  long  unless  c
 * "comm", "ucmd", "ucomm"  are all the same:  short unless -f
397
398
 * ( determinations are made in display.c, we mostly deal with results ) */
static int pr_args(char *restrict const outbuf, const proc_t *restrict const pp){
albert's avatar
albert committed
399
  char *endp = outbuf;
400
401
402
403
404
  int rightward = max_rightward;
  int fh = forest_helper(outbuf);

  endp += fh;
  rightward -= fh;
albert's avatar
albert committed
405

406
  if(pp->cmdline && !bsd_c_option)
407
    endp += escaped_copy(endp, *pp->cmdline, OUTBUF_SIZE_AT(endp), &rightward);
408
  else
409
    endp += escape_command(endp, pp, OUTBUF_SIZE_AT(endp), &rightward, ESC_DEFUNCT);
410

411
  if(bsd_e_option && rightward>1 && OUTBUF_SIZE_AT(endp)>1) {
412
413
414
    if(pp->environ && *pp->environ) {
      *endp++ = ' ';
      rightward--;
415
      endp += escape_strlist(endp, pp->environ, OUTBUF_SIZE_AT(endp), &rightward);
416
    }
417
418
419
420
421
422
423
424
425
426
  }
  return max_rightward-rightward;
}

/*
 * "args", "cmd", "command" are all the same:  long  unless  c
 * "comm", "ucmd", "ucomm"  are all the same:  short unless -f
 * ( determinations are made in display.c, we mostly deal with results ) */
static int pr_comm(char *restrict const outbuf, const proc_t *restrict const pp){
  char *endp = outbuf;
427
428
429
430
431
  int rightward = max_rightward;
  int fh = forest_helper(outbuf);

  endp += fh;
  rightward -= fh;
432
433

  if(pp->cmdline && unix_f_option)
434
    endp += escaped_copy(endp, *pp->cmdline, OUTBUF_SIZE_AT(endp), &rightward);
435
  else
436
    endp += escape_command(endp, pp, OUTBUF_SIZE_AT(endp), &rightward, ESC_DEFUNCT);
437

438
  if(bsd_e_option && rightward>1 && OUTBUF_SIZE_AT(endp)>1) {
439
440
441
    if(pp->environ && *pp->environ) {
      *endp++ = ' ';
      rightward--;
442
      endp += escape_strlist(endp, pp->environ, OUTBUF_SIZE_AT(endp), &rightward);
443
    }
csmall's avatar
csmall committed
444
  }
albert's avatar
albert committed
445
  return max_rightward-rightward;
csmall's avatar
csmall committed
446
447
}

448
static int pr_cgname(char *restrict const outbuf, const proc_t *restrict const pp){
449
  int rightward = max_rightward;
450

451
  escaped_copy(outbuf, pp->cgname, OUTBUF_SIZE, &rightward);
452
  return max_rightward-rightward;
Jan Görig's avatar
Jan Görig committed
453
454
}

455
static int pr_cgroup(char *restrict const outbuf,const proc_t *restrict const pp) {
Craig Small's avatar
Craig Small committed
456
  int rightward = max_rightward;
457
458
459

  escaped_copy(outbuf, *pp->cgroup, OUTBUF_SIZE, &rightward);
  return max_rightward-rightward;
Craig Small's avatar
Craig Small committed
460
461
}

csmall's avatar
csmall committed
462
/* Non-standard, from SunOS 5 */
albert's avatar
albert committed
463
static int pr_fname(char *restrict const outbuf, const proc_t *restrict const pp){
albert's avatar
albert committed
464
465
  char *endp = outbuf;
  int rightward = max_rightward;
466
467
468
469
  int fh = forest_helper(outbuf);

  endp += fh;
  rightward -= fh;
470

albert's avatar
albert committed
471
472
  if (rightward>8)  /* 8=default, but forest maybe feeds more */
    rightward = 8;
473

474
  endp += escape_str(endp, pp->cmd, OUTBUF_SIZE_AT(endp), &rightward);
albert's avatar
albert committed
475
476
  //return endp - outbuf;
  return max_rightward-rightward;
csmall's avatar
csmall committed
477
478
}

479
480
#undef OUTBUF_SIZE_AT

csmall's avatar
csmall committed
481
/* elapsed wall clock time, [[dd-]hh:]mm:ss format (not same as "time") */
albert's avatar
albert committed
482
static int pr_etime(char *restrict const outbuf, const proc_t *restrict const pp){
483
  unsigned long t;
albert's avatar
albert committed
484
  unsigned dd,hh,mm,ss;
csmall's avatar
csmall committed
485
  char *cp = outbuf;
486
  t = cook_etime(pp);
csmall's avatar
csmall committed
487
488
489
490
491
492
493
494
495
496
497
498
499
  ss = t%60;
  t /= 60;
  mm = t%60;
  t /= 60;
  hh = t%24;
  t /= 24;
  dd = t;
  cp +=(     dd      ?  snprintf(cp, COLWID, "%u-", dd)           :  0 );
  cp +=( (dd || hh)  ?  snprintf(cp, COLWID, "%02u:", hh)         :  0 );
  cp +=                 snprintf(cp, COLWID, "%02u:%02u", mm, ss)       ;
  return (int)(cp-outbuf);
}

500
501
/* elapsed wall clock time in seconds */
static int pr_etimes(char *restrict const outbuf, const proc_t *restrict const pp){
502
  unsigned t = cook_etime(pp);
503
504
505
  return snprintf(outbuf, COLWID, "%u", t);
}

csmall's avatar
csmall committed
506
/* "Processor utilisation for scheduling."  --- we use %cpu w/o fraction */
albert's avatar
albert committed
507
static int pr_c(char *restrict const outbuf, const proc_t *restrict const pp){
albert's avatar
albert committed
508
  unsigned long long total_time;   /* jiffies used by this process */
albert's avatar
albert committed
509
  unsigned pcpu = 0;               /* scaled %cpu, 99 means 99% */
albert's avatar
albert committed
510
  unsigned long long seconds;      /* seconds of process life */
csmall's avatar
csmall committed
511
512
  total_time = pp->utime + pp->stime;
  if(include_dead_children) total_time += (pp->cutime + pp->cstime);
513
  seconds = cook_etime(pp);
csmall's avatar
csmall committed
514
  if(seconds) pcpu = (total_time * 100ULL / Hertz) / seconds;
albert's avatar
albert committed
515
516
  if (pcpu > 99U) pcpu = 99U;
  return snprintf(outbuf, COLWID, "%2u", pcpu);
csmall's avatar
csmall committed
517
518
}
/* normal %CPU in ##.# format. */
albert's avatar
albert committed
519
static int pr_pcpu(char *restrict const outbuf, const proc_t *restrict const pp){
albert's avatar
albert committed
520
521
522
  unsigned long long total_time;   /* jiffies used by this process */
  unsigned pcpu = 0;               /* scaled %cpu, 999 means 99.9% */
  unsigned long long seconds;      /* seconds of process life */
csmall's avatar
csmall committed
523
524
  total_time = pp->utime + pp->stime;
  if(include_dead_children) total_time += (pp->cutime + pp->cstime);
525
  seconds = cook_etime(pp);
csmall's avatar
csmall committed
526
  if(seconds) pcpu = (total_time * 1000ULL / Hertz) / seconds;
albert's avatar
albert committed
527
528
529
  if (pcpu > 999U)
    return snprintf(outbuf, COLWID, "%u", pcpu/10U);
  return snprintf(outbuf, COLWID, "%u.%u", pcpu/10U, pcpu%10U);
csmall's avatar
csmall committed
530
531
}
/* this is a "per-mill" format, like %cpu with no decimal point */
albert's avatar
albert committed
532
static int pr_cp(char *restrict const outbuf, const proc_t *restrict const pp){
albert's avatar
albert committed
533
534
535
  unsigned long long total_time;   /* jiffies used by this process */
  unsigned pcpu = 0;               /* scaled %cpu, 999 means 99.9% */
  unsigned long long seconds;      /* seconds of process life */
csmall's avatar
csmall committed
536
537
  total_time = pp->utime + pp->stime;
  if(include_dead_children) total_time += (pp->cutime + pp->cstime);
538
  seconds = cook_etime(pp);
csmall's avatar
csmall committed
539
  if(seconds) pcpu = (total_time * 1000ULL / Hertz) / seconds;
albert's avatar
albert committed
540
541
  if (pcpu > 999U) pcpu = 999U;
  return snprintf(outbuf, COLWID, "%3u", pcpu);
csmall's avatar
csmall committed
542
543
}

albert's avatar
albert committed
544
static int pr_pgid(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
545
546
  return snprintf(outbuf, COLWID, "%u", pp->pgrp);
}
albert's avatar
albert committed
547
static int pr_ppid(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
548
549
550
551
552
  return snprintf(outbuf, COLWID, "%u", pp->ppid);
}


/* cumulative CPU time, [dd-]hh:mm:ss format (not same as "etime") */
albert's avatar
albert committed
553
static int pr_time(char *restrict const outbuf, const proc_t *restrict const pp){
554
  unsigned long t;
albert's avatar
albert committed
555
  unsigned dd,hh,mm,ss;
csmall's avatar
csmall committed
556
  int c;
557
  t = cook_time(pp);
csmall's avatar
csmall committed
558
559
560
561
562
563
564
565
566
567
568
569
  ss = t%60;
  t /= 60;
  mm = t%60;
  t /= 60;
  hh = t%24;
  t /= 24;
  dd = t;
  c  =( dd ? snprintf(outbuf, COLWID, "%u-", dd) : 0              );
  c +=( snprintf(outbuf+c, COLWID, "%02u:%02u:%02u", hh, mm, ss)    );
  return c;
}

570
571
572
573
574
575
/* cumulative CPU time in seconds (not same as "etimes") */
static int pr_times(char *restrict const outbuf, const proc_t *restrict const pp){
  unsigned t = cook_time(pp);
  return snprintf(outbuf, COLWID, "%u", t);
}

csmall's avatar
csmall committed
576
577
578
579
580
581
582
583
/* HP-UX puts this (I forget, vsz or vsize?) in kB and uses "sz" for pages.
 * Unix98 requires "vsz" to be kB.
 * Tru64 does both vsize and vsz like "1.23M"
 *
 * Our pp->vm_size is kB and our pp->vsize is pages.
 *
 * TODO: add flag for "1.23M" behavior, on this and other columns.
 */
albert's avatar
albert committed
584
static int pr_vsz(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
585
586
587
  return snprintf(outbuf, COLWID, "%lu", pp->vm_size);
}

albert's avatar
albert committed
588
//////////////////////////////////////////////////////////////////////////////////////
csmall's avatar
csmall committed
589

590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
// "PRI" is created by "opri", or by "pri" when -c is used.
//
// Unix98 only specifies that a high "PRI" is low priority.
// Sun and SCO add the -c behavior. Sun defines "pri" and "opri".
// Linux may use "priority" for historical purposes.
//
// According to the kernel's fs/proc/array.c and kernel/sched.c source,
// the kernel reports it in /proc via this:
//        p->prio - MAX_RT_PRIO
// such that "RT tasks are offset by -200. Normal tasks are centered
// around 0, value goes from -16 to +15" but who knows if that is
// before or after the conversion...
//
// <linux/sched.h> says:
// MAX_RT_PRIO is currently 100.       (so we see 0 in /proc)
// RT tasks have a p->prio of 0 to 99. (so we see -100 to -1)
// non-RT tasks are from 100 to 139.   (so we see 0 to 39)
// Lower values have higher priority, as in the UNIX standard.
//
// In any case, pp->priority+100 should get us back to what the kernel
// has for p->prio.
//
// Test results with the "yes" program on a 2.6.x kernel:
//
// # ps -C19,_20 -o pri,opri,intpri,priority,ni,pcpu,pid,comm
// PRI PRI PRI PRI  NI %CPU  PID COMMAND
//   0  99  99  39  19 10.6 8686 19
//  34  65  65   5 -20 94.7 8687 _20
//
// Grrr. So the UNIX standard "PRI" must NOT be from "pri".
// Either of the others will do. We use "opri" for this.
// (and use "pri" when the "-c" option is used)
// Probably we should have Linux-specific "pri_for_l" and "pri_for_lc"
//
// sched_get_priority_min.2 says the Linux static priority is
// 1..99 for RT and 0 for other... maybe 100 is kernel-only?
//
// A nice range would be -99..0 for RT and 1..40 for normal,
// which is pp->priority+1. (3-digit max, positive is normal,
// negative or 0 is RT, and meets the standard for PRI)
//
albert's avatar
albert committed
631
632

// legal as UNIX "PRI"
633
// "priority"         (was -20..20, now -100..39)
albert's avatar
albert committed
634
static int pr_priority(char *restrict const outbuf, const proc_t *restrict const pp){    /* -20..20 */
csmall's avatar
csmall committed
635
636
    return snprintf(outbuf, COLWID, "%ld", pp->priority);
}
albert's avatar
albert committed
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663

// legal as UNIX "PRI"
// "intpri" and "opri" (was 39..79, now  -40..99)
static int pr_opri(char *restrict const outbuf, const proc_t *restrict const pp){        /* 39..79 */
    return snprintf(outbuf, COLWID, "%ld", 60 + pp->priority);
}

// legal as UNIX "PRI"
// "pri_foo"   --  match up w/ nice values of sleeping processes (-120..19)
static int pr_pri_foo(char *restrict const outbuf, const proc_t *restrict const pp){
    return snprintf(outbuf, COLWID, "%ld", pp->priority - 20);
}

// legal as UNIX "PRI"
// "pri_bar"   --  makes RT pri show as negative       (-99..40)
static int pr_pri_bar(char *restrict const outbuf, const proc_t *restrict const pp){
    return snprintf(outbuf, COLWID, "%ld", pp->priority + 1);
}

// legal as UNIX "PRI"
// "pri_baz"   --  the kernel's ->prio value, as of Linux 2.6.8     (1..140)
static int pr_pri_baz(char *restrict const outbuf, const proc_t *restrict const pp){
    return snprintf(outbuf, COLWID, "%ld", pp->priority + 100);
}


// not legal as UNIX "PRI"
664
// "pri"               (was 20..60, now    0..139)
albert's avatar
albert committed
665
static int pr_pri(char *restrict const outbuf, const proc_t *restrict const pp){         /* 20..60 */
csmall's avatar
csmall committed
666
667
    return snprintf(outbuf, COLWID, "%ld", 39 - pp->priority);
}
albert's avatar
albert committed
668
669
670
671
672
673
674

// not legal as UNIX "PRI"
// "pri_api"   --  match up w/ RT API    (-40..99)
static int pr_pri_api(char *restrict const outbuf, const proc_t *restrict const pp){
    return snprintf(outbuf, COLWID, "%ld", -1 - pp->priority);
}

675
676
677
678
// Linux applies nice value in the scheduling policies (classes)
// SCHED_OTHER(0) and SCHED_BATCH(3).  Ref: sched_setscheduler(2).
// Also print nice value for old kernels which didn't use scheduling
// policies (-1).
albert's avatar
albert committed
679
static int pr_nice(char *restrict const outbuf, const proc_t *restrict const pp){
680
  if(pp->sched!=0 && pp->sched!=3 && pp->sched!=-1) return snprintf(outbuf, COLWID, "-");
albert's avatar
albert committed
681
  return snprintf(outbuf, COLWID, "%ld", pp->nice);
csmall's avatar
csmall committed
682
683
}

albert's avatar
albert committed
684
685
686
687
688
689
690
691
692
693
694
695
696
// HP-UX   "cls": RT RR RR2 ???? HPUX FIFO KERN
// Solaris "class": SYS TS FX IA RT FSS (FIFO is RR w/ Inf quant)
//                  FIFO+RR share RT; FIFO has Inf quant
//                  IA=interactive; FX=fixed; TS=timeshare; SYS=system
//                  FSS=fairshare; INTS=interrupts
// Tru64   "policy": FF RR TS
// IRIX    "class": RT TS B BC WL GN
//                  RT=real-time; TS=time-share; B=batch; BC=batch-critical
//                  WL=weightless; GN=gang-scheduled
//                  see miser(1) for this; PRI has some letter codes too
static int pr_class(char *restrict const outbuf, const proc_t *restrict const pp){
  switch(pp->sched){
  case -1: return snprintf(outbuf, COLWID, "-");   // not reported
697
  case  0: return snprintf(outbuf, COLWID, "TS");  // SCHED_OTHER SCHED_NORMAL
albert's avatar
albert committed
698
699
  case  1: return snprintf(outbuf, COLWID, "FF");  // SCHED_FIFO
  case  2: return snprintf(outbuf, COLWID, "RR");  // SCHED_RR
albert's avatar
albert committed
700
  case  3: return snprintf(outbuf, COLWID, "B");   // SCHED_BATCH
701
702
  case  4: return snprintf(outbuf, COLWID, "ISO"); // reserved for SCHED_ISO (Con Kolivas)
  case  5: return snprintf(outbuf, COLWID, "IDL"); // SCHED_IDLE
Martin Polednik's avatar
Martin Polednik committed
703
  case  6: return snprintf(outbuf, COLWID, "DLN"); // SCHED_DEADLINE
albert's avatar
albert committed
704
  case  7: return snprintf(outbuf, COLWID, "#7");  //
albert's avatar
albert committed
705
  case  8: return snprintf(outbuf, COLWID, "#8");  //
albert's avatar
albert committed
706
  case  9: return snprintf(outbuf, COLWID, "#9");  //
albert's avatar
albert committed
707
708
709
710
711
712
713
714
715
716
  default: return snprintf(outbuf, COLWID, "?");   // unknown value
  }
}
// Based on "type", FreeBSD would do:
//    REALTIME  "real:%u", prio
//    NORMAL    "normal"
//    IDLE      "idle:%u", prio
//    default   "%u:%u", type, prio
// We just print the priority, and have other keywords for type.
static int pr_rtprio(char *restrict const outbuf, const proc_t *restrict const pp){
Sami Kerola's avatar
Sami Kerola committed
717
  if(pp->sched==0 || pp->sched==(unsigned long)-1) return snprintf(outbuf, COLWID, "-");
albert's avatar
albert committed
718
719
720
  return snprintf(outbuf, COLWID, "%ld", pp->rtprio);
}
static int pr_sched(char *restrict const outbuf, const proc_t *restrict const pp){
Sami Kerola's avatar
Sami Kerola committed
721
  if(pp->sched==(unsigned long)-1) return snprintf(outbuf, COLWID, "-");
albert's avatar
albert committed
722
723
724
725
726
  return snprintf(outbuf, COLWID, "%ld", pp->sched);
}

////////////////////////////////////////////////////////////////////////////////

albert's avatar
albert committed
727
static int pr_wchan(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
728
729
730
731
732
733
734
735
736
737
738
/*
 * Unix98 says "blank if running" and also "no blanks"! :-(
 * Unix98 also says to use '-' if something is meaningless.
 * Digital uses both '*' and '-', with undocumented differences.
 * (the '*' for -1 (rare) and the '-' for 0)
 * Sun claims to use a blank AND use '-', in the same man page.
 * Perhaps "blank" should mean '-'.
 *
 * AIX uses '-' for running processes, the location when there is
 * only one thread waiting in the kernel, and '*' when there is
 * more than one thread waiting in the kernel.
albert's avatar
albert committed
739
740
741
 *
 * The output should be truncated to maximal columns width -- overflow
 * is not supported for the "wchan".
csmall's avatar
csmall committed
742
 */
743
744
745
746
  const char *w;
  size_t len;
  if(!(pp->wchan & 0xffffff)) return memcpy(outbuf,"-",2),1;
  if(wchan_is_number) return snprintf(outbuf, COLWID, "%x", (unsigned)(pp->wchan) & 0xffffffu);
747
  w = lookup_wchan(pp->XXXID);
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
  len = strlen(w);
  if(len>max_rightward) len=max_rightward;
  memcpy(outbuf, w, len);
  outbuf[len] = '\0';
  return len;
}

static int pr_wname(char *restrict const outbuf, const proc_t *restrict const pp){
/* SGI's IRIX always uses a number for "wchan", so "wname" is provided too.
 *
 * We use '-' for running processes, the location when there is
 * only one thread waiting in the kernel, and '*' when there is
 * more than one thread waiting in the kernel.
 *
 * The output should be truncated to maximal columns width -- overflow
 * is not supported for the "wchan".
 */
  const char *w;
  size_t len;
  if(!(pp->wchan & 0xffffff)) return memcpy(outbuf,"-",2),1;
768
  w = lookup_wchan(pp->XXXID);
769
770
771
772
773
774
775
776
777
778
  len = strlen(w);
  if(len>max_rightward) len=max_rightward;
  memcpy(outbuf, w, len);
  outbuf[len] = '\0';
  return len;
}

static int pr_nwchan(char *restrict const outbuf, const proc_t *restrict const pp){
  if(!(pp->wchan & 0xffffff)) return memcpy(outbuf,"-",2),1;
  return snprintf(outbuf, COLWID, "%x", (unsigned)(pp->wchan) & 0xffffffu);
csmall's avatar
csmall committed
779
780
781
782
}

/* Terrible trunctuation, like BSD crap uses: I999 J999 K999 */
/* FIXME: disambiguate /dev/tty69 and /dev/pts/69. */
albert's avatar
albert committed
783
static int pr_tty4(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
784
/* snprintf(outbuf, COLWID, "%02x:%02x", pp->tty>>8, pp->tty&0xff); */
albert's avatar
albert committed
785
  return dev_to_tty(outbuf, 4, pp->tty, pp->XXXID, ABBREV_DEV|ABBREV_TTY|ABBREV_PTS);
csmall's avatar
csmall committed
786
787
788
}

/* Unix98: format is unspecified, but must match that used by who(1). */
albert's avatar
albert committed
789
static int pr_tty8(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
790
/* snprintf(outbuf, COLWID, "%02x:%02x", pp->tty>>8, pp->tty&0xff); */
791
  return dev_to_tty(outbuf, COLWID, pp->tty, pp->XXXID, ABBREV_DEV);
csmall's avatar
csmall committed
792
793
794
795
}

#if 0
/* This BSD state display may contain spaces, which is illegal. */
albert's avatar
albert committed
796
static int pr_oldstate(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
797
798
799
800
    return snprintf(outbuf, COLWID, "%s", status(pp));
}
#endif

albert's avatar
albert committed
801
// This state display is Unix98 compliant and has lots of info like BSD.
albert's avatar
albert committed
802
static int pr_stat(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
803
804
    int end = 0;
    outbuf[end++] = pp->state;
805
806
807
//  if(pp->rss==0 && pp->state!='Z')  outbuf[end++] = 'W'; // useless "swapped out"
    if(pp->nice < 0)                  outbuf[end++] = '<';
    if(pp->nice > 0)                  outbuf[end++] = 'N';
albert's avatar
albert committed
808
809
810
811
812
813
// In this order, NetBSD would add:
//     traced   'X'
//     systrace 'x'
//     exiting  'E' (not printed for zombies)
//     vforked  'V'
//     system   'K' (and do not print 'L' too)
814
815
    if(pp->vm_lock)                   outbuf[end++] = 'L';
    if(pp->session == pp->tgid)       outbuf[end++] = 's'; // session leader
albert's avatar
albert committed
816
    if(pp->nlwp > 1)                  outbuf[end++] = 'l'; // multi-threaded
817
    if(pp->pgrp == pp->tpgid)         outbuf[end++] = '+'; // in foreground process group
csmall's avatar
csmall committed
818
819
820
821
822
    outbuf[end] = '\0';
    return end;
}

/* This minimal state display is Unix98 compliant, like SCO and SunOS 5 */
albert's avatar
albert committed
823
static int pr_s(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
824
825
826
827
828
    outbuf[0] = pp->state;
    outbuf[1] = '\0';
    return 1;
}

albert's avatar
albert committed
829
static int pr_flag(char *restrict const outbuf, const proc_t *restrict const pp){
albert's avatar
albert committed
830
831
    /* Unix98 requires octal flags */
    /* this user-hostile and volatile junk gets 1 character */
albert's avatar
albert committed
832
    return snprintf(outbuf, COLWID, "%o", (unsigned)(pp->flags>>6U)&0x7U);
csmall's avatar
csmall committed
833
834
}

albert's avatar
albert committed
835
// plus these: euid,ruid,egroup,rgroup (elsewhere in this file)
csmall's avatar
csmall committed
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850

/*********** non-standard ***********/

/*** BSD
sess	session pointer
(SCO has:Process session leader ID as a decimal value. (SESSION))
jobc	job control count
cpu	short-term cpu usage factor (for scheduling)
sl	sleep time (in seconds; 127 = infinity)
re	core residency time (in seconds; 127 = infinity)
pagein	pageins (same as majflt)
lim	soft memory limit
tsiz	text size (in Kbytes)
***/

albert's avatar
albert committed
851
static int pr_stackp(char *restrict const outbuf, const proc_t *restrict const pp){
852
    return snprintf(outbuf, COLWID, "%0*lx", (int)(2*sizeof(long)), pp->start_stack);
csmall's avatar
csmall committed
853
854
}

albert's avatar
albert committed
855
static int pr_esp(char *restrict const outbuf, const proc_t *restrict const pp){
856
    return snprintf(outbuf, COLWID, "%0*lx", (int)(2*sizeof(long)), pp->kstk_esp);
csmall's avatar
csmall committed
857
858
}

albert's avatar
albert committed
859
static int pr_eip(char *restrict const outbuf, const proc_t *restrict const pp){
860
    return snprintf(outbuf, COLWID, "%0*lx", (int)(2*sizeof(long)), pp->kstk_eip);
csmall's avatar
csmall committed
861
862
863
}

/* This function helps print old-style time formats */
albert's avatar
albert committed
864
static int old_time_helper(char *dst, unsigned long long t, unsigned long long rel) {
csmall's avatar
csmall committed
865
  if(!t)            return snprintf(dst, COLWID, "    -");
albert's avatar
albert committed
866
867
  if(t == ~0ULL)    return snprintf(dst, COLWID, "   xx");
  if((long long)(t-=rel) < 0)  t=0ULL;
Sami Kerola's avatar
Sami Kerola committed
868
  if(t>9999ULL)     return snprintf(dst, COLWID, "%5llu", t/100ULL);
albert's avatar
albert committed
869
  else              return snprintf(dst, COLWID, "%2u.%02u", (unsigned)t/100U, (unsigned)t%100U);
csmall's avatar
csmall committed
870
871
}

albert's avatar
albert committed
872
static int pr_bsdtime(char *restrict const outbuf, const proc_t *restrict const pp){
albert's avatar
albert committed
873
874
    unsigned long long t;
    unsigned u;
csmall's avatar
csmall committed
875
876
    t = pp->utime + pp->stime;
    if(include_dead_children) t += (pp->cutime + pp->cstime);
albert's avatar
albert committed
877
878
    u = t / Hertz;
    return snprintf(outbuf, COLWID, "%3u:%02u", u/60U, u%60U);
csmall's avatar
csmall committed
879
880
}

albert's avatar
albert committed
881
static int pr_bsdstart(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
882
883
  time_t start;
  time_t seconds_ago;
884
  start = getbtime() + pp->start_time / Hertz;
csmall's avatar
csmall committed
885
886
  seconds_ago = seconds_since_1970 - start;
  if(seconds_ago < 0) seconds_ago=0;
887
888
  if(seconds_ago > 3600*24)  snprintf(outbuf, COLWID, "%s", ctime(&start)+4);
  else                       snprintf(outbuf, COLWID, "%s", ctime(&start)+10);
csmall's avatar
csmall committed
889
890
891
892
  outbuf[6] = '\0';
  return 6;
}

albert's avatar
albert committed
893
static int pr_alarm(char *restrict const outbuf, const proc_t *restrict const pp){
894
    return old_time_helper(outbuf, pp->alarm, 0ULL);
csmall's avatar
csmall committed
895
896
897
}

/* HP-UX puts this in pages and uses "vsz" for kB */
albert's avatar
albert committed
898
static int pr_sz(char *restrict const outbuf, const proc_t *restrict const pp){
899
  return snprintf(outbuf, COLWID, "%lu", (pp->vm_size)/(page_size/1024));
csmall's avatar
csmall committed
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
}


/*
 * FIXME: trs,drs,tsiz,dsiz,m_trs,m_drs,vm_exe,vm_data,trss
 * I suspect some/all of those are broken. They seem to have been
 * inherited by Linux and AIX from early BSD systems. FreeBSD only
 * retains tsiz. The prefixed versions come from Debian.
 * Sun and Digital have none of this crap. The code here comes
 * from an old Linux ps, and might not be correct for ELF executables.
 *
 * AIX            TRS    size of resident-set (real memory) of text
 * AIX            TSIZ   size of text (shared-program) image
 * FreeBSD        tsiz   text size (in Kbytes)
 * 4.3BSD NET/2   trss   text resident set size (in Kbytes)
 * 4.3BSD NET/2   tsiz   text size (in Kbytes)
 */

/* kB data size. See drs, tsiz & trs. */
albert's avatar
albert committed
919
static int pr_dsiz(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
920
921
922
923
924
925
    long dsiz = 0;
    if(pp->vsize) dsiz += (pp->vsize - pp->end_code + pp->start_code) >> 10;
    return snprintf(outbuf, COLWID, "%ld", dsiz);
}

/* kB text (code) size. See trs, dsiz & drs. */
albert's avatar
albert committed
926
static int pr_tsiz(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
927
928
929
930
931
932
    long tsiz = 0;
    if(pp->vsize) tsiz += (pp->end_code - pp->start_code) >> 10;
    return snprintf(outbuf, COLWID, "%ld", tsiz);
}

/* kB _resident_ data size. See dsiz, tsiz & trs. */
albert's avatar
albert committed
933
static int pr_drs(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
934
935
936
937
938
939
    long drs = 0;
    if(pp->vsize) drs += (pp->vsize - pp->end_code + pp->start_code) >> 10;
    return snprintf(outbuf, COLWID, "%ld", drs);
}

/* kB text _resident_ (code) size. See tsiz, dsiz & drs. */
albert's avatar
albert committed
940
static int pr_trs(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
941
942
943
944
945
    long trs = 0;
    if(pp->vsize) trs += (pp->end_code - pp->start_code) >> 10;
    return snprintf(outbuf, COLWID, "%ld", trs);
}

946
/* approximation to: kB of address space that could end up in swap */
albert's avatar
albert committed
947
static int pr_swapable(char *restrict const outbuf, const proc_t *restrict const pp){
948
949
  return snprintf(outbuf, COLWID, "%ld", pp->vm_data + pp->vm_stack);
}
csmall's avatar
csmall committed
950

albert's avatar
albert committed
951
/* nasty old Debian thing */
albert's avatar
albert committed
952
static int pr_size(char *restrict const outbuf, const proc_t *restrict const pp){
albert's avatar
albert committed
953
954
955
  return snprintf(outbuf, COLWID, "%ld", pp->size);
}

csmall's avatar
csmall committed
956

albert's avatar
albert committed
957
static int pr_minflt(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
958
959
960
961
962
    long flt = pp->min_flt;
    if(include_dead_children) flt += pp->cmin_flt;
    return snprintf(outbuf, COLWID, "%ld", flt);
}

albert's avatar
albert committed
963
static int pr_majflt(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
964
965
966
967
968
    long flt = pp->maj_flt;
    if(include_dead_children) flt += pp->cmaj_flt;
    return snprintf(outbuf, COLWID, "%ld", flt);
}

albert's avatar
albert committed
969
static int pr_lim(char *restrict const outbuf, const proc_t *restrict const pp){
albert's avatar
albert committed
970
971
972
973
974
975
    if(pp->rss_rlim == RLIM_INFINITY){
      outbuf[0] = 'x';
      outbuf[1] = 'x';
      outbuf[2] = '\0';
      return 2;
    }
csmall's avatar
csmall committed
976
977
978
979
    return snprintf(outbuf, COLWID, "%5ld", pp->rss_rlim >> 10);
}

/* should print leading tilde ('~') if process is bound to the CPU */
albert's avatar
albert committed
980
static int pr_psr(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
981
982
983
  return snprintf(outbuf, COLWID, "%d", pp->processor);
}

984
985
986
987
988
989
static int pr_numa(char *restrict const outbuf, const proc_t *restrict const pp){
  static int first = 1;
  if (first) { numa_init(); first = 0; }   // we'll keep this dependency local
  return snprintf(outbuf, COLWID, "%d", numa_node_of_cpu(pp->processor));
}

albert's avatar
albert committed
990
static int pr_rss(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
991
992
993
994
  return snprintf(outbuf, COLWID, "%lu", pp->vm_rss);
}

/* pp->vm_rss * 1000 would overflow on 32-bit systems with 64 GB memory */
albert's avatar
albert committed
995
static int pr_pmem(char *restrict const outbuf, const proc_t *restrict const pp){
csmall's avatar
csmall committed
996
997
998
999
1000
  unsigned long pmem = 0;
  pmem = pp->vm_rss * 1000ULL / kb_main_total;
  if (pmem > 999) pmem = 999;
  return snprintf(outbuf, COLWID, "%2u.%u", (unsigned)(pmem/10), (unsigned)(pmem%10));
}