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
10 #include "xiosysincludes.h"
19 #include <sys/resource.h> /* RLIMIT_CPU ... */
20 #include <dirent.h> /* opendir() readdir() closedir() */
25 /* Search dir recursively for matching device file.
27 returns -1 when it failed to find the device file. */
35 struct dirent
*dirent
;
36 char devpath
[PATH_MAX
];
39 /* Pass 1: search dir flatly for this device entry */
40 dirp
= opendir(dirname
);
42 Warn2("failed to open dir \"%s\": %s", dirname
, strerror(errno
));
45 while ((errno
= 0) || (dirent
= readdir(dirp
))) {
48 #if HAVE_DIRENT_D_TYPE
49 if (dirent
->d_type
!= DT_CHR
&& dirent
->d_type
!= DT_UNKNOWN
)
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
));
57 if ((statbuf
.st_mode
& S_IFMT
) != S_IFCHR
)
59 if ((statbuf
.st_rdev
>> 8) == major
&&
60 (statbuf
.st_rdev
& 0xff) == minor
) {
61 strcpy(devname
, devpath
);
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
);
75 Warn2("failed to open dir \"%s\": %s", dirname
, strerror(errno
));
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
)
86 if (Stat(dirent
->d_name
, &statbuf
) < 0)
88 if ((statbuf
.st_mode
& S_IFMT
) != S_IFDIR
)
92 if (!strcmp(dirent
->d_name
, ".") || !strcmp(dirent
->d_name
, ".."))
94 snprintf(dirpath
, PATH_MAX
, "%s/%s", dirname
, dirent
->d_name
);
95 rc
= find_devpath(dirpath
, major
, minor
, devname
);
101 if (dirent
== NULL
) {
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(
114 char cttypath
[PATH_MAX
+1];
117 { /* On Linux this just gives "/dev/tty" */
119 fprintf(outfile
, "controlling terminal by ctermid(): \"%s\"\n", ctermid(s
));
122 { /* Check if there is a controlling terminal */
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
));
129 fprintf(outfile
, "controlling terminal by /dev/tty, ttyname(): (none)\n");
133 do { /* Linux: derive ctty from info in /proc */
134 const char procpath
[] = "/proc/self/stat";
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
);
146 n
= fscanf(procstat
, "%*s %*s %*s %*s %*s %*s %u", &dev
);
148 Warn1("failed to read ctty info from \"%s\"", procpath
);
153 min
= ((dev
>>12)&0xfff00)|(dev
&0xff);
154 rc
= find_devpath("/dev" /* _PATH_DEV has trailing "/" */, maj
, min
, cttypath
);
156 snprintf(cttypath
, PATH_MAX
, "device %u, %u", maj
, min
);
162 #else /* !HAVE_PROC_DIR */
164 #endif /* !HAVE_PROC_DIR */
166 fprintf(outfile
, "controlling terminal by /proc/<pid>/: \"%s\"\n", cttypath
);
168 fprintf(outfile
, "controlling terminal by /proc/<pid>/: (none)\n");
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());
183 fprintf(outfile
, "process session id = "F_pid
"\n", Getsid(0));
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");
200 char procpath
[PATH_MAX
];
201 sprintf(procpath
, "/proc/"F_pid
"/status", Getpid());
210 fprintf(outfile
, "umask = "F_mode
"\n", mask
);
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
));
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
));
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
));
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
));
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
));
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
));
258 "max resident set size %24"F_rlim_max
"%24"F_rlim_max
"\n",
259 rlim
.rlim_cur
, rlim
.rlim_max
);
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
));
267 "max user processes %24"F_rlim_max
"%24"F_rlim_max
"\n",
268 rlim
.rlim_cur
, rlim
.rlim_max
);
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
));
276 "open files %24"F_rlim_max
"%24"F_rlim_max
"\n",
277 rlim
.rlim_cur
, rlim
.rlim_max
);
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
));
285 "max locked-in-memory\n address space %24"F_rlim_max
"%24"F_rlim_max
"\n",
286 rlim
.rlim_cur
, rlim
.rlim_max
);
290 if (getrlimit(RLIMIT_AS
, &rlim
) < 0) {
291 Warn2("getrlimit(RLIMIT_AS, %p): %s", &rlim
, strerror(errno
));
294 "virtual memory (kbytes) %24"F_rlim_max
"%24"F_rlim_max
"\n",
295 rlim
.rlim_cur
, rlim
.rlim_max
);
298 fputc('\n', outfile
);
303 fprintf(outfile
, "// CC: "CC
"\n");
305 #ifdef __STDC_VERSION__
306 fprintf(outfile
, "#define __STDC_VERSION__ %ld\n", __STDC_VERSION__
);
309 fprintf(outfile
, "SIZE_MAX = "F_Zu
" /* maximum value of size_t */\n", SIZE_MAX
);
312 fprintf(outfile
, "P_tmpdir = \"%s\"\n", P_tmpdir
);
315 fprintf(outfile
, "L_tmpnam = %u\n", L_tmpnam
);
318 fprintf(outfile
, "TMP_MAX = %d\n", TMP_MAX
);
321 fprintf(outfile
, "FD_SETSIZE = %d /* maximum number of FDs for select() */\n", FD_SETSIZE
);
324 fprintf(outfile
, "PIPE_BUF = %-24d\n", PIPE_BUF
);
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?? */