Version 1.8.0.1
[socat.git] / procan.c
blob22dd5e484bac32c439beb0bad25aa27389c4b8ad
1 /* source: procan.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* the subroutine procan makes a "PROCess ANalysis". It gathers information
6 about the process environment it is running in without modifying its state
7 (almost).
8 */
10 #include "xiosysincludes.h"
11 #include "mytypes.h"
12 #include "compat.h"
13 #include "error.h"
14 #include "sycls.h"
15 #include "sysutils.h"
16 #include "sched.h"
17 #include "filan.h"
19 #include <sys/resource.h> /* RLIMIT_CPU ... */
20 #include <dirent.h> /* opendir() readdir() closedir() */
22 #include "procan.h"
25 /* Search dir recursively for matching device file.
26 Returns 0 on success;
27 returns -1 when it failed to find the device file. */
28 int find_devpath(
29 char *dirname,
30 unsigned int major,
31 unsigned int minor,
32 char *devname)
34 DIR *dirp;
35 struct dirent *dirent;
36 char devpath[PATH_MAX];
37 int rc;
39 /* Pass 1: search dir flatly for this device entry */
40 dirp = opendir(dirname);
41 if (dirp == NULL) {
42 Warn2("failed to open dir \"%s\": %s", dirname, strerror(errno));
43 return -1;
45 while ((errno = 0) || (dirent = readdir(dirp))) {
46 struct stat statbuf;
48 #if HAVE_DIRENT_D_TYPE
49 if (dirent->d_type != DT_CHR && dirent->d_type != DT_UNKNOWN)
50 continue;
51 #endif
52 snprintf(devpath, PATH_MAX, "%s/%s", dirname, dirent->d_name);
53 if (Stat(devpath, &statbuf) < 0) {
54 Warn2("failed to stat entry \"%s\": %s", devpath, strerror(errno));
55 continue;
57 if ((statbuf.st_mode & S_IFMT) != S_IFCHR)
58 continue;
59 if ((statbuf.st_rdev >> 8) == major &&
60 (statbuf.st_rdev & 0xff) == minor) {
61 strcpy(devname, devpath);
62 return 0;
64 continue;
66 closedir(dirp);
67 if (errno != 0) {
68 Warn2("failed to read dir \"%s\": %s", dirname, strerror(errno));
69 snprintf(devname, PATH_MAX, "device %u, %u", major, minor);
72 /* Pass 2: search sub dirs */
73 dirp = opendir(dirname);
74 if (dirp == NULL) {
75 Warn2("failed to open dir \"%s\": %s", dirname, strerror(errno));
76 return -1;
78 while ((errno = 0) || (dirent = readdir(dirp))) {
79 char dirpath[PATH_MAX];
80 #if HAVE_DIRENT_D_TYPE
81 if (dirent->d_type != DT_DIR)
82 continue;
83 #else /* Solaris */
85 struct stat statbuf;
86 if (Stat(dirent->d_name, &statbuf) < 0)
87 continue;
88 if ((statbuf.st_mode & S_IFMT) != S_IFDIR)
89 continue;
91 #endif
92 if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, ".."))
93 continue;
94 snprintf(dirpath, PATH_MAX, "%s/%s", dirname, dirent->d_name);
95 rc = find_devpath(dirpath, major, minor, devname);
96 if (rc == 0) {
97 return 0;
100 closedir(dirp);
101 if (dirent == NULL) {
102 return 1;
104 return 0;
107 /* Tries to determine the name of the controlling terminal.
108 Returns 0 on success, the name in cttyname;
109 returns 1 when only the device numbers are in cttyname;
110 returns -1 when it failed to determine ctty. */
111 static int controlling_term(
112 FILE *outfile)
114 char cttypath[PATH_MAX+1];
115 int rc;
117 { /* On Linux this just gives "/dev/tty" */
118 char s[L_ctermid+1];
119 fprintf(outfile, "controlling terminal by ctermid(): \"%s\"\n", ctermid(s));
122 { /* Check if there is a controlling terminal */
123 int fd;
125 if ((fd = Open("/dev/tty", O_NOCTTY, 0)) >= 0)
126 /* On Linux this just gives "/dev/tty" */
127 fprintf(outfile, "controlling terminal by /dev/tty, ttyname(): \"%s\"\n", Ttyname(fd));
128 else
129 fprintf(outfile, "controlling terminal by /dev/tty, ttyname(): (none)\n");
132 #if HAVE_PROC_DIR
133 do { /* Linux: derive ctty from info in /proc */
134 const char procpath[] = "/proc/self/stat";
135 FILE *procstat;
136 unsigned int dev;
137 int n = 0;
138 unsigned int maj, min;
140 /* Linux: get device ids from /proc */
141 if ((procstat = fopen(procpath, "r")) == NULL) {
142 Warn1("failed to open \"%s\" for process info", procpath);
143 rc = -1;
144 break;
146 n = fscanf(procstat, "%*s %*s %*s %*s %*s %*s %u", &dev);
147 if (n != 1) {
148 Warn1("failed to read ctty info from \"%s\"", procpath);
149 rc = -1;
150 break;
152 maj = (dev>>8)&0xff;
153 min = ((dev>>12)&0xfff00)|(dev&0xff);
154 rc = find_devpath("/dev" /* _PATH_DEV has trailing "/" */, maj, min, cttypath);
155 if (rc < 0) {
156 snprintf(cttypath, PATH_MAX, "device %u, %u", maj, min);
157 rc = 1;
158 break;
160 rc = 0;
161 } while (false);
162 #else /* !HAVE_PROC_DIR */
163 rc = -1;
164 #endif /* !HAVE_PROC_DIR */
165 if (rc >= 0)
166 fprintf(outfile, "controlling terminal by /proc/<pid>/: \"%s\"\n", cttypath);
167 else
168 fprintf(outfile, "controlling terminal by /proc/<pid>/: (none)\n");
170 return 0;
174 int procan(FILE *outfile) {
176 /*filan(0, outfile);*/
178 fprintf(outfile, "process id = "F_pid"\n", Getpid());
179 fprintf(outfile, "process parent id = "F_pid"\n", Getppid());
180 controlling_term(outfile);
181 fprintf(outfile, "process group id = "F_pid"\n", Getpgrp());
182 #if HAVE_GETSID
183 fprintf(outfile, "process session id = "F_pid"\n", Getsid(0));
184 #endif
185 fprintf(outfile, "process group id if fg process / stdin = "F_pid"\n", Tcgetpgrp(0));
186 fprintf(outfile, "process group id if fg process / stdout = "F_pid"\n", Tcgetpgrp(1));
187 fprintf(outfile, "process group id if fg process / stderr = "F_pid"\n", Tcgetpgrp(2));
189 /* process owner, groups */
190 fprintf(outfile, "user id = "F_uid"\n", Getuid());
191 fprintf(outfile, "effective user id = "F_uid"\n", Geteuid());
192 fprintf(outfile, "group id = "F_gid"\n", Getgid());
193 fprintf(outfile, "effective group id = "F_gid"\n", Getegid());
195 /* Simple process features */
196 fprintf(outfile, "\n");
198 mode_t mask;
199 #if LATER
200 char procpath[PATH_MAX];
201 sprintf(procpath, "/proc/"F_pid"/status", Getpid());
202 if (Stat()) {
204 } else
205 #endif
207 mask = Umask(0066);
208 Umask(mask);
210 fprintf(outfile, "umask = "F_mode"\n", mask);
214 struct rlimit rlim;
216 fprintf(outfile, "\n/* Resource limits */\n");
217 fprintf(outfile, "resource current maximum\n");
218 if (getrlimit(RLIMIT_CPU, &rlim) < 0) {
219 Warn2("getrlimit(RLIMIT_CPU, %p): %s", &rlim, strerror(errno));
220 } else {
221 fprintf(outfile,
222 "cpu time (seconds) %24"F_rlim_max"%24"F_rlim_max"\n",
223 rlim.rlim_cur, rlim.rlim_max);
225 if (getrlimit(RLIMIT_FSIZE, &rlim) < 0) {
226 Warn2("getrlimit(RLIMIT_FSIZE, %p): %s", &rlim, strerror(errno));
227 } else {
228 fprintf(outfile,
229 "file size (blocks) %24"F_rlim_max"%24"F_rlim_max"\n",
230 rlim.rlim_cur, rlim.rlim_max);
232 if (getrlimit(RLIMIT_DATA, &rlim) < 0) {
233 Warn2("getrlimit(RLIMIT_DATA, %p): %s", &rlim, strerror(errno));
234 } else {
235 fprintf(outfile,
236 "data seg size (kbytes) %24"F_rlim_max"%24"F_rlim_max"\n",
237 rlim.rlim_cur, rlim.rlim_max);
239 if (getrlimit(RLIMIT_STACK, &rlim) < 0) {
240 Warn2("getrlimit(RLIMIT_STACK, %p): %s", &rlim, strerror(errno));
241 } else {
242 fprintf(outfile,
243 "stack size (blocks) %24"F_rlim_max"%24"F_rlim_max"\n",
244 rlim.rlim_cur, rlim.rlim_max);
246 if (getrlimit(RLIMIT_CORE, &rlim) < 0) {
247 Warn2("getrlimit(RLIMIT_CORE, %p): %s", &rlim, strerror(errno));
248 } else {
249 fprintf(outfile,
250 "core file size (blocks) %24"F_rlim_max"%24"F_rlim_max"\n",
251 rlim.rlim_cur, rlim.rlim_max);
253 #ifdef RLIMIT_RSS /* Linux, AIX; not Cygwin */
254 if (getrlimit(RLIMIT_RSS, &rlim) < 0) {
255 Warn2("getrlimit(RLIMIT_RSS, %p): %s", &rlim, strerror(errno));
256 } else {
257 fprintf(outfile,
258 "max resident set size %24"F_rlim_max"%24"F_rlim_max"\n",
259 rlim.rlim_cur, rlim.rlim_max);
261 #endif
262 #ifdef RLIMIT_NPROC /* Linux, not AIX, Cygwin */
263 if (getrlimit(RLIMIT_NPROC, &rlim) < 0) {
264 Warn2("getrlimit(RLIMIT_NPROC, %p): %s", &rlim, strerror(errno));
265 } else {
266 fprintf(outfile,
267 "max user processes %24"F_rlim_max"%24"F_rlim_max"\n",
268 rlim.rlim_cur, rlim.rlim_max);
270 #endif
271 #ifdef RLIMIT_NOFILE /* not AIX 4.1 */
272 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
273 Warn2("getrlimit(RLIMIT_NOFILE, %p): %s", &rlim, strerror(errno));
274 } else {
275 fprintf(outfile,
276 "open files %24"F_rlim_max"%24"F_rlim_max"\n",
277 rlim.rlim_cur, rlim.rlim_max);
279 #endif
280 #ifdef RLIMIT_MEMLOCK /* Linux, not AIX, Cygwin */
281 if (getrlimit(RLIMIT_MEMLOCK, &rlim) < 0) {
282 Warn2("getrlimit(RLIMIT_MEMLOCK, %p): %s", &rlim, strerror(errno));
283 } else {
284 fprintf(outfile,
285 "max locked-in-memory\n address space %24"F_rlim_max"%24"F_rlim_max"\n",
286 rlim.rlim_cur, rlim.rlim_max);
288 #endif
289 #ifdef RLIMIT_AS
290 if (getrlimit(RLIMIT_AS, &rlim) < 0) {
291 Warn2("getrlimit(RLIMIT_AS, %p): %s", &rlim, strerror(errno));
292 } else {
293 fprintf(outfile,
294 "virtual memory (kbytes) %24"F_rlim_max"%24"F_rlim_max"\n",
295 rlim.rlim_cur, rlim.rlim_max);
297 #endif
298 fputc('\n', outfile);
302 #ifdef CC
303 fprintf(outfile, "// CC: "CC"\n");
304 #endif
305 #ifdef __STDC_VERSION__
306 fprintf(outfile, "#define __STDC_VERSION__ %ld\n", __STDC_VERSION__);
307 #endif
308 #ifdef SIZE_MAX
309 fprintf(outfile, "SIZE_MAX = "F_Zu" /* maximum value of size_t */\n", SIZE_MAX);
310 #endif
311 #ifdef P_tmpdir
312 fprintf(outfile, "P_tmpdir = \"%s\"\n", P_tmpdir);
313 #endif
314 #ifdef L_tmpnam
315 fprintf(outfile, "L_tmpnam = %u\n", L_tmpnam);
316 #endif
317 #ifdef TMP_MAX
318 fprintf(outfile, "TMP_MAX = %d\n", TMP_MAX);
319 #endif
320 #ifdef FD_SETSIZE
321 fprintf(outfile, "FD_SETSIZE = %d /* maximum number of FDs for select() */\n", FD_SETSIZE);
322 #endif
323 #ifdef PIPE_BUF
324 fprintf(outfile, "PIPE_BUF = %-24d\n", PIPE_BUF);
325 #endif
327 /* Name spaces */
329 char path[PATH_MAX];
330 char link[PATH_MAX];
331 snprintf(path, sizeof(path)-1, "/proc/"F_pid"/ns/net", getpid());
332 if (readlink(path, link, sizeof(link)-1) >= 0) {
333 fprintf(outfile, "Network namespace: %s", link);
337 /* file descriptors */
339 /* what was this for?? */
340 /*Sleep(1);*/
341 return 0;