1/* See LICENSE file for copyright and license details. */
2
3#include <sys/types.h>
4
5#include <dirent.h>
6#include <libgen.h>
7#include <limits.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <unistd.h>
12
13#include "proc.h"
14#include "queue.h"
15#include "util.h"
16
17struct pidentry {
18 pid_t pid;
19 SLIST_ENTRY(pidentry) entry;
20};
21
22static SLIST_HEAD(, pidentry) omitpid_head;
23
24static void
25usage(void)
26{
27 eprintf("usage: %s [-o pid1,pid2,...pidN] [-s] [program...]\n", argv0);
28}
29
30// ?man pidof: find process ids
31// ?man arguments: -o pid1
32// ?man find the process identity numbers of running programs
33int
34main(int argc, char *argv[])
35{
36 DIR *dp;
37 struct dirent *entry;
38 pid_t pid;
39 struct procstat ps;
40 char cmdline[BUFSIZ], *cmd, *cmdbase = NULL, *p, *arg = NULL;
41 int i, found = 0;
42 int sflag = 0, oflag = 0;
43 struct pidentry *pe;
44
45 ARGBEGIN
46 {
47 // ?man -s: silent mode or print summary
48 case 's':
49 sflag = 1;
50 break;
51 // ?man -o:str: specify output file
52 case 'o':
53 oflag = 1;
54 arg = EARGF(usage());
55 break;
56 default:
57 usage();
58 }
59 ARGEND;
60
61 if (!argc)
62 return 1;
63
64 SLIST_INIT(&omitpid_head);
65
66 if (oflag) {
67 for (p = strtok(arg, ","); p; p = strtok(NULL, ",")) {
68 pe = emalloc(sizeof(*pe));
69 if (strcmp(p, "%PPID") == 0)
70 pe->pid = getppid();
71 else
72 pe->pid = estrtol(p, 10);
73 SLIST_INSERT_HEAD(&omitpid_head, pe, entry);
74 }
75 }
76
77 if (!(dp = opendir("/proc")))
78 eprintf("opendir /proc:");
79
80 while ((entry = readdir(dp))) {
81 if (!pidfile(entry->d_name))
82 continue;
83 pid = estrtol(entry->d_name, 10);
84 if (oflag) {
85 SLIST_FOREACH(pe, &omitpid_head, entry)
86 if (pe->pid == pid)
87 break;
88 if (pe)
89 continue;
90 }
91 if (parsestat(pid, &ps) < 0)
92 continue;
93 if (parsecmdline(ps.pid, cmdline, sizeof(cmdline)) < 0) {
94 cmd = ps.comm;
95 cmdbase = cmd;
96 } else {
97 if ((p = strchr(cmdline, ' ')))
98 *p = '\0';
99 cmd = cmdline;
100 cmdbase = basename(cmdline);
101 }
102 /* Workaround for login shells */
103 if (cmd[0] == '-')
104 cmd++;
105 for (i = 0; i < argc; i++) {
106 if (strcmp(cmd, argv[i]) == 0 || strcmp(cmdbase, argv[i]) == 0) {
107 putword(stdout, entry->d_name);
108 found++;
109 if (sflag)
110 goto out;
111 }
112 }
113 }
114
115out:
116 if (found)
117 putchar('\n');
118
119 closedir(dp);
120
121 return found ? 0 : 1;
122}