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