summaryrefslogtreecommitdiff
path: root/docs/handbook/corebinutils/ps.md
blob: cbbd749a44ffacc21ff026709f59f2991d48acfb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
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
# ps — Process Status

## Overview

`ps` displays information about active processes. This implementation
reads process data from the Linux `/proc` filesystem and presents it
through BSD-style format strings. It provides a custom `struct kinfo_proc`
that mirrors FreeBSD's interface while reading from Linux procfs.

**Source**: `ps/ps.c`, `ps/ps.h`, `ps/fmt.c`, `ps/keyword.c`,
`ps/print.c`, `ps/nlist.c`, `ps/extern.h`
**Origin**: BSD 4.4, University of California, Berkeley
**License**: BSD-3-Clause

## Synopsis

```
ps [-AaCcdefHhjLlMmrSTuvwXxZ] [-D fmt] [-G gid[,gid...]]
   [-J jail] [-N system] [-O fmt] [-o fmt] [-p pid[,pid...]]
   [-t tty[,tty...]] [-U user[,user...]] [-g group[,group...]]
```

## Source Architecture

### File Responsibilities

| File | Purpose |
|------|---------|
| `ps.c` | Main program, option parsing, process collection |
| `ps.h` | Data structures, constants, STAILQ macros |
| `fmt.c` | Format string parsing and column management |
| `keyword.c` | Format keyword definitions and lookup table |
| `print.c` | Column value formatters (PID, user, CPU, etc.) |
| `nlist.c` | Name list support (noop on Linux) |
| `extern.h` | Cross-file function declarations |

### Key Data Structures

#### Process Information (Linux replacement for BSD kinfo_proc)

```c
struct kinfo_proc {
    pid_t   ki_pid;        /* Process ID */
    pid_t   ki_ppid;       /* Parent PID */
    pid_t   ki_pgid;       /* Process group ID */
    pid_t   ki_sid;        /* Session ID */
    uid_t   ki_uid;        /* Real UID */
    uid_t   ki_ruid;       /* Real UID (copy) */
    uid_t   ki_svuid;      /* Saved UID */
    gid_t   ki_rgid;       /* Real GID */
    gid_t   ki_svgid;      /* Saved GID */
    gid_t   ki_groups[KI_NGROUPS]; /* Supplementary groups */
    int     ki_ngroups;    /* Number of groups */
    dev_t   ki_tdev;       /* TTY device */
    int     ki_flag;       /* Process flags */
    int     ki_stat;       /* Process state */
    char    ki_comm[COMMLEN + 1]; /* Command name */
    char    ki_wmesg[WMESGLEN + 1]; /* Wait channel */
    int     ki_nice;       /* Nice value */
    int     ki_pri;        /* Priority */
    long    ki_size;       /* Virtual size */
    long    ki_rssize;     /* Resident size */
    struct timeval ki_start; /* Start time */
    struct timeval ki_rusage; /* Resource usage */
    /* ... additional fields ... */
};
```

#### KINFO Wrapper

```c
typedef struct {
    struct kinfo_proc *ki_p;
    char *ki_args;      /* Full command line */
    char *ki_env;       /* Environment (if -E) */
    double ki_pcpu;     /* Computed %CPU */
    long ki_memsize;    /* Computed memory size */
} KINFO;
```

#### Format Variable

```c
typedef struct {
    const char *name;    /* Keyword name (e.g., "pid", "user") */
    const char *header;  /* Column header (e.g., "PID", "USER") */
    int width;           /* Column width */
    int (*sprnt)(KINFO *); /* Print function */
    int flag;            /* Format flags */
} VAR;
```

### Constants

```c
#define COMMLEN   256   /* Max command name length */
#define WMESGLEN  64    /* Max wait message length */
#define KI_NGROUPS 16   /* Max supplementary groups tracked */
```

### musl Compatibility

FreeBSD uses `STAILQ_*` macros extensively, but musl's `<sys/queue.h>`
may not provide them. `ps.h` defines custom implementations:

```c
#ifndef STAILQ_HEAD
#define STAILQ_HEAD(name, type)                         \
struct name {                                           \
    struct type *stqh_first;                            \
    struct type **stqh_last;                            \
}
#define STAILQ_ENTRY(type)                              \
struct {                                                \
    struct type *stqe_next;                             \
}
#define STAILQ_INIT(head) do { ... } while (0)
#define STAILQ_INSERT_TAIL(head, elm, field) do { ... } while (0)
#define STAILQ_FOREACH(var, head, field) ...
#endif
```

### Predefined Format Strings

```c
/* Default format (-f not specified) */
const char *dfmt = "pid,tt,stat,time,command";

/* Jobs format (-j) */
const char *jfmt = "user,pid,ppid,pgid,sid,jobc,stat,tt,time,command";

/* Long format (-l) */
const char *lfmt = "uid,pid,ppid,cpu,pri,nice,vsz,rss,wchan,stat,tt,time,command";

/* User format (-u) */
const char *ufmt = "user,pid,%cpu,%mem,vsz,rss,tt,stat,start,time,command";

/* Virtual memory format (-v) */
const char *vfmt = "pid,stat,time,sl,re,pagein,vsz,rss,lim,tsiz,%cpu,%mem,command";
```

### /proc Parsing

Process data is read from multiple `/proc/[pid]/` files:

| File | Data Extracted |
|------|----------------|
| `/proc/[pid]/stat` | PID, PPID, PGID, state, priority, nice, threads, start time |
| `/proc/[pid]/status` | UID, GID, groups, memory (VmSize, VmRSS) |
| `/proc/[pid]/cmdline` | Full command line arguments |
| `/proc/[pid]/environ` | Environment variables (if requested) |
| `/proc/[pid]/wchan` | Wait channel name |
| `/proc/[pid]/fd/0` | Controlling TTY detection |

### Process Filtering

```c
/* Option string */
#define PS_ARGS "AaCcD:defG:gHhjJ:LlM:mN:O:o:p:rSTt:U:uvwXxZ"

struct listinfo {
    int count;
    int maxcount;
    int *list;        /* Array of values to match */
    int (*addelem)(struct listinfo *, const char *);
};
```

Filtering by PID, UID, GID, TTY, session, and process group uses
`struct listinfo` with dynamic arrays and element-specific parsers.

### Column Formatting (keyword.c)

The keyword table maps format names to print functions:

```c
static VAR var[] = {
    {"pid",     "PID",     5, s_pid,     0},
    {"ppid",    "PPID",    5, s_ppid,    0},
    {"user",    "USER",    8, s_user,    0},
    {"uid",     "UID",     5, s_uid,     0},
    {"gid",     "GID",     5, s_gid,     0},
    {"%cpu",    "%CPU",    4, s_pcpu,    0},
    {"%mem",    "%MEM",    4, s_pmem,    0},
    {"vsz",     "VSZ",     6, s_vsz,     0},
    {"rss",     "RSS",     5, s_rss,     0},
    {"tt",      "TT",      3, s_tty,     0},
    {"stat",    "STAT",    4, s_stat,    0},
    {"time",    "TIME",    8, s_time,    0},
    {"command", "COMMAND", 16, s_command, COMM},
    {"args",    "COMMAND", 16, s_args,    COMM},
    {"comm",    "COMMAND", 16, s_comm,    COMM},
    {"nice",    "NI",      3, s_nice,    0},
    {"pri",     "PRI",     3, s_pri,     0},
    {"wchan",   "WCHAN",   8, s_wchan,   0},
    {"start",   "STARTED", 8, s_start,   0},
    /* ... more keywords ... */
    {NULL, NULL, 0, NULL, 0},  /* Sentinel */
};
```

### Global State

```c
int cflag;          /* Raw CPU usage */
int eval;           /* Exit value */
time_t now;         /* Current time */
int rawcpu;         /* Don't compute decay */
int sumrusage;      /* Sum child usage */
int termwidth;      /* Terminal width */
int showthreads;    /* Show threads (-H) */
int hlines;         /* Header repeat interval */
```

## Options Reference

| Flag | Description |
|------|-------------|
| `-A` / `-e` | All processes |
| `-a` | Processes with terminals (except session leaders) |
| `-C` | Raw CPU percentage |
| `-c` | Show command name only (not full path) |
| `-d` | All except session leaders |
| `-f` | Full format |
| `-G gid` | Filter by real group ID |
| `-g group` | Filter by group name |
| `-H` | Show threads |
| `-h` | Repeat header every screenful |
| `-j` | Jobs format |
| `-L` | Show all threads (LWP) |
| `-l` | Long format |
| `-M` | Display MAC label |
| `-m` | Sort by memory usage |
| `-O fmt` | Add columns to default format |
| `-o fmt` | Custom output format |
| `-p pid` | Filter by PID |
| `-r` | Running processes only |
| `-S` | Include child time |
| `-T` | Show threads for current terminal |
| `-t tty` | Filter by TTY |
| `-U user` | Filter by effective user |
| `-u` | User format |
| `-v` | Virtual memory format |
| `-w` | Wide output |
| `-X` | Skip processes without controlling TTY |
| `-x` | Include processes without controlling TTY |
| `-Z` | Show security context |

## System Calls Used

| Syscall | Purpose |
|---------|---------|
| `opendir(3)` / `readdir(3)` | Enumerate `/proc/` PIDs |
| `open(2)` / `read(2)` | Read `/proc/[pid]/*` files |
| `stat(2)` | Get file owner for UID detection |
| `getpwuid(3)` / `getgrgid(3)` | UID/GID to name resolution |
| `ioctl(TIOCGWINSZ)` | Terminal width |
| `sysconf(3)` | Clock ticks, page size |

## Examples

```sh
# Default process list
ps

# All processes, user format
ps aux

# Full format
ps -ef

# Custom columns
ps -o pid,user,%cpu,%mem,command

# Filter by user
ps -U root

# Jobs format
ps -j

# Long format with threads
ps -lH
```

## Exit Codes

| Code | Meaning |
|------|---------|
| 0    | Success |
| 1    | Error |

## Linux-Specific Notes

- Reads from `/proc` filesystem instead of BSD `kvm_getprocs(3)`
- Custom `struct kinfo_proc` replaces BSD's `<sys/user.h>` variant
- STAILQ macros defined inline for musl compatibility
- No jail (`-J`) support on Linux
- No Capsicum sandboxing