1#include "capsicum-test.h"
2
3#ifdef __FreeBSD__
4#include <sys/param.h>
5#include <sys/proc.h>
6#include <sys/queue.h>
7#include <sys/socket.h>
8#include <sys/sysctl.h>
9#include <sys/user.h>
10#include <libprocstat.h>
11#endif
12
13#include <stdio.h>
14#include <string.h>
15#include <signal.h>
16
17#include <map>
18#include <vector>
19#include <string>
20
21bool verbose = false;
22bool tmpdir_on_tmpfs = false;
23bool force_mt = false;
24bool force_nofork = false;
25uid_t other_uid = 0;
26
27namespace {
28std::map<std::string, std::string> tmp_paths;
29}
30
31const char *TmpFile(const char *p) {
32  std::string pathname(p);
33  if (tmp_paths.find(pathname) == tmp_paths.end()) {
34    std::string fullname = tmpdir + "/" + pathname;
35    tmp_paths[pathname] = fullname;
36  }
37  return tmp_paths[pathname].c_str();
38}
39
40char ProcessState(int pid) {
41#ifdef __linux__
42  // Open the process status file.
43  char s[1024];
44  snprintf(s, sizeof(s), "/proc/%d/status", pid);
45  FILE *f = fopen(s, "r");
46  if (f == NULL) return '\0';
47
48  // Read the file line by line looking for the state line.
49  const char *prompt = "State:\t";
50  while (!feof(f)) {
51    fgets(s, sizeof(s), f);
52    if (!strncmp(s, prompt, strlen(prompt))) {
53      fclose(f);
54      return s[strlen(prompt)];
55    }
56  }
57  fclose(f);
58  return '?';
59#endif
60#ifdef __FreeBSD__
61  // First check if the process exists/we have permission to see it. This
62  // Avoids warning messages being printed to stderr by libprocstat.
63  size_t len = 0;
64  int name[4];
65  name[0] = CTL_KERN;
66  name[1] = KERN_PROC;
67  name[2] = KERN_PROC_PID;
68  name[3] = pid;
69  if (sysctl(name, nitems(name), NULL, &len, NULL, 0) < 0 && errno == ESRCH) {
70    if (verbose) fprintf(stderr, "Process %d does not exist\n", pid);
71    return '\0'; // No such process.
72  }
73  unsigned int count = 0;
74  struct procstat *prstat = procstat_open_sysctl();
75  EXPECT_NE(nullptr, prstat) << "procstat_open_sysctl failed.";
76  errno = 0;
77  struct kinfo_proc *p = procstat_getprocs(prstat, KERN_PROC_PID, pid, &count);
78  if (p == NULL || count == 0) {
79    if (verbose) {
80      fprintf(stderr, "procstat_getprocs failed with %p/%d: %s\n", (void *)p,
81              count, strerror(errno));
82    }
83    procstat_close(prstat);
84    return '\0';
85  }
86  char result = '\0';
87  // See state() in bin/ps/print.c
88  switch (p->ki_stat) {
89  case SSTOP:
90    result = 'T';
91    break;
92  case SSLEEP:
93    if (p->ki_tdflags & TDF_SINTR) /* interruptable (long) */
94      result = 'S';
95    else
96      result = 'D';
97    break;
98  case SRUN:
99  case SIDL:
100    result = 'R';
101    break;
102  case SWAIT:
103  case SLOCK:
104    // We treat SWAIT/SLOCK as 'S' here (instead of 'W'/'L').
105    result = 'S';
106    break;
107  case SZOMB:
108    result = 'Z';
109    break;
110  default:
111    result = '?';
112    break;
113  }
114  procstat_freeprocs(prstat, p);
115  procstat_close(prstat);
116  if (verbose) fprintf(stderr, "Process %d in state '%c'\n", pid, result);
117  return result;
118#endif
119}
120