2008-01-28 21:37:16 +00:00
|
|
|
/* source: procan.c */
|
2016-07-22 06:54:31 +00:00
|
|
|
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
|
2008-01-27 12:00:08 +00:00
|
|
|
/* Published under the GNU General Public License V.2, see file COPYING */
|
|
|
|
|
|
|
|
/* the subroutine procan makes a "PROCess ANalysis". It gathers information
|
|
|
|
about the process environment it is running in without modifying its state
|
|
|
|
(almost).
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "xiosysincludes.h"
|
|
|
|
#include "mytypes.h"
|
|
|
|
#include "compat.h"
|
|
|
|
#include "error.h"
|
|
|
|
#include "sycls.h"
|
|
|
|
#include "sysutils.h"
|
2023-07-21 05:10:38 +00:00
|
|
|
#include "sched.h"
|
2008-01-27 12:00:08 +00:00
|
|
|
#include "filan.h"
|
|
|
|
|
2023-11-11 16:45:02 +00:00
|
|
|
#include <sys/resource.h> /* RLIMIT_CPU ... */
|
|
|
|
#include <dirent.h> /* opendir() readdir() closedir() */
|
2008-01-27 12:00:08 +00:00
|
|
|
|
|
|
|
#include "procan.h"
|
|
|
|
|
|
|
|
|
2023-11-11 16:45:02 +00:00
|
|
|
/* Search dir recursively for matching device file.
|
|
|
|
Returns 0 on success;
|
|
|
|
returns -1 when it failed to find the device file. */
|
|
|
|
int find_devpath(
|
|
|
|
char *dirname,
|
|
|
|
unsigned int major,
|
|
|
|
unsigned int minor,
|
|
|
|
char *devname)
|
|
|
|
{
|
|
|
|
DIR *dirp;
|
|
|
|
struct dirent *dirent;
|
|
|
|
char devpath[PATH_MAX];
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/* Pass 1: search dir flatly for this device entry */
|
|
|
|
dirp = opendir(dirname);
|
|
|
|
if (dirp == NULL) {
|
|
|
|
Warn2("failed to open dir \"%s\": %s", dirname, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
while ((errno = 0) || (dirent = readdir(dirp))) {
|
|
|
|
struct stat statbuf;
|
|
|
|
|
|
|
|
#if HAVE_DIRENT_D_TYPE
|
|
|
|
if (dirent->d_type != DT_CHR && dirent->d_type != DT_UNKNOWN)
|
|
|
|
continue;
|
|
|
|
#endif
|
|
|
|
snprintf(devpath, PATH_MAX, "%s/%s", dirname, dirent->d_name);
|
|
|
|
if (Stat(devpath, &statbuf) < 0) {
|
|
|
|
Warn2("failed to stat entry \"%s\": %s", devpath, strerror(errno));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((statbuf.st_mode & S_IFMT) != S_IFCHR)
|
|
|
|
continue;
|
|
|
|
if ((statbuf.st_rdev >> 8) == major &&
|
|
|
|
(statbuf.st_rdev & 0xff) == minor) {
|
|
|
|
strcpy(devname, devpath);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
closedir(dirp);
|
|
|
|
if (errno != 0) {
|
|
|
|
Warn2("failed to read dir \"%s\": %s", dirname, strerror(errno));
|
|
|
|
snprintf(devname, PATH_MAX, "device %u, %u", major, minor);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Pass 2: search sub dirs */
|
|
|
|
dirp = opendir(dirname);
|
|
|
|
if (dirp == NULL) {
|
|
|
|
Warn2("failed to open dir \"%s\": %s", dirname, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
while ((errno = 0) || (dirent = readdir(dirp))) {
|
|
|
|
char dirpath[PATH_MAX];
|
|
|
|
#if HAVE_DIRENT_D_TYPE
|
|
|
|
if (dirent->d_type != DT_DIR)
|
|
|
|
continue;
|
|
|
|
#else /* Solaris */
|
|
|
|
{
|
|
|
|
struct stat statbuf;
|
|
|
|
if (Stat(dirent->d_name, &statbuf) < 0)
|
|
|
|
continue;
|
|
|
|
if ((statbuf.st_mode & S_IFMT) != S_IFDIR)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, ".."))
|
|
|
|
continue;
|
|
|
|
snprintf(dirpath, PATH_MAX, "%s/%s", dirname, dirent->d_name);
|
|
|
|
rc = find_devpath(dirpath, major, minor, devname);
|
|
|
|
if (rc == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
closedir(dirp);
|
|
|
|
if (dirent == NULL) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Tries to determine the name of the controlling terminal.
|
|
|
|
Returns 0 on success, the name in cttyname;
|
|
|
|
returns 1 when only the device numbers are in cttyname;
|
|
|
|
returns -1 when it failed to determine ctty. */
|
|
|
|
static int controlling_term(
|
|
|
|
FILE *outfile)
|
|
|
|
{
|
|
|
|
char cttypath[PATH_MAX+1];
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
{ /* On Linux this just gives "/dev/tty" */
|
|
|
|
char s[L_ctermid+1];
|
|
|
|
fprintf(outfile, "controlling terminal by ctermid(): \"%s\"\n", ctermid(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
{ /* Check if there is a controlling terminal */
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if ((fd = Open("/dev/tty", O_NOCTTY, 0)) >= 0)
|
|
|
|
/* On Linux this just gives "/dev/tty" */
|
|
|
|
fprintf(outfile, "controlling terminal by /dev/tty, ttyname(): \"%s\"\n", Ttyname(fd));
|
|
|
|
else
|
|
|
|
fprintf(outfile, "controlling terminal by /dev/tty, ttyname(): (none)\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
#if HAVE_PROC_DIR
|
|
|
|
do { /* Linux: derive ctty from info in /proc */
|
|
|
|
const char procpath[] = "/proc/self/stat";
|
|
|
|
FILE *procstat;
|
|
|
|
unsigned int dev;
|
|
|
|
int n = 0;
|
|
|
|
unsigned int maj, min;
|
|
|
|
|
|
|
|
/* Linux: get device ids from /proc */
|
|
|
|
if ((procstat = fopen(procpath, "r")) == NULL) {
|
|
|
|
Warn1("failed to open \"%s\" for process info", procpath);
|
|
|
|
rc = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
n = fscanf(procstat, "%*s %*s %*s %*s %*s %*s %u", &dev);
|
|
|
|
if (n != 1) {
|
|
|
|
Warn1("failed to read ctty info from \"%s\"", procpath);
|
|
|
|
rc = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
maj = (dev>>8)&0xff;
|
|
|
|
min = ((dev>>12)&0xfff00)|(dev&0xff);
|
|
|
|
rc = find_devpath("/dev" /* _PATH_DEV has trailing "/" */, maj, min, cttypath);
|
|
|
|
if (rc < 0) {
|
|
|
|
snprintf(cttypath, PATH_MAX, "device %u, %u", maj, min);
|
|
|
|
rc = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
} while (false);
|
|
|
|
#else /* !HAVE_PROC_DIR */
|
|
|
|
rc = -1;
|
|
|
|
#endif /* !HAVE_PROC_DIR */
|
|
|
|
if (rc >= 0)
|
|
|
|
fprintf(outfile, "controlling terminal by /proc/<pid>/: \"%s\"\n", cttypath);
|
|
|
|
else
|
|
|
|
fprintf(outfile, "controlling terminal by /proc/<pid>/: (none)\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-27 12:00:08 +00:00
|
|
|
int procan(FILE *outfile) {
|
|
|
|
|
|
|
|
/*filan(0, outfile);*/
|
|
|
|
|
|
|
|
fprintf(outfile, "process id = "F_pid"\n", Getpid());
|
|
|
|
fprintf(outfile, "process parent id = "F_pid"\n", Getppid());
|
2023-11-11 16:45:02 +00:00
|
|
|
controlling_term(outfile);
|
2008-01-27 12:00:08 +00:00
|
|
|
fprintf(outfile, "process group id = "F_pid"\n", Getpgrp());
|
|
|
|
#if HAVE_GETSID
|
|
|
|
fprintf(outfile, "process session id = "F_pid"\n", Getsid(0));
|
|
|
|
#endif
|
|
|
|
fprintf(outfile, "process group id if fg process / stdin = "F_pid"\n", Tcgetpgrp(0));
|
|
|
|
fprintf(outfile, "process group id if fg process / stdout = "F_pid"\n", Tcgetpgrp(1));
|
|
|
|
fprintf(outfile, "process group id if fg process / stderr = "F_pid"\n", Tcgetpgrp(2));
|
|
|
|
|
|
|
|
/* process owner, groups */
|
|
|
|
fprintf(outfile, "user id = "F_uid"\n", Getuid());
|
|
|
|
fprintf(outfile, "effective user id = "F_uid"\n", Geteuid());
|
|
|
|
fprintf(outfile, "group id = "F_gid"\n", Getgid());
|
|
|
|
fprintf(outfile, "effective group id = "F_gid"\n", Getegid());
|
|
|
|
|
2023-11-11 16:40:52 +00:00
|
|
|
/* Simple process features */
|
|
|
|
fprintf(outfile, "\n");
|
|
|
|
{
|
|
|
|
mode_t mask;
|
|
|
|
#if LATER
|
|
|
|
char procpath[PATH_MAX];
|
|
|
|
sprintf(procpath, "/proc/"F_pid"/status", Getpid());
|
|
|
|
if (Stat()) {
|
|
|
|
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
mask = Umask(0066);
|
|
|
|
Umask(mask);
|
|
|
|
}
|
|
|
|
fprintf(outfile, "umask = "F_mode"\n", mask);
|
|
|
|
}
|
|
|
|
|
2008-01-27 12:00:08 +00:00
|
|
|
{
|
|
|
|
struct rlimit rlim;
|
|
|
|
|
2023-11-11 16:40:52 +00:00
|
|
|
fprintf(outfile, "\n/* Resource limits */\n");
|
2014-02-03 10:04:09 +00:00
|
|
|
fprintf(outfile, "resource current maximum\n");
|
2008-01-27 12:00:08 +00:00
|
|
|
if (getrlimit(RLIMIT_CPU, &rlim) < 0) {
|
|
|
|
Warn2("getrlimit(RLIMIT_CPU, %p): %s", &rlim, strerror(errno));
|
|
|
|
} else {
|
|
|
|
fprintf(outfile,
|
2014-02-03 10:04:09 +00:00
|
|
|
"cpu time (seconds) %24"F_rlim_max"%24"F_rlim_max"\n",
|
2008-01-27 12:00:08 +00:00
|
|
|
rlim.rlim_cur, rlim.rlim_max);
|
|
|
|
}
|
|
|
|
if (getrlimit(RLIMIT_FSIZE, &rlim) < 0) {
|
|
|
|
Warn2("getrlimit(RLIMIT_FSIZE, %p): %s", &rlim, strerror(errno));
|
|
|
|
} else {
|
|
|
|
fprintf(outfile,
|
2014-02-03 10:04:09 +00:00
|
|
|
"file size (blocks) %24"F_rlim_max"%24"F_rlim_max"\n",
|
2008-01-27 12:00:08 +00:00
|
|
|
rlim.rlim_cur, rlim.rlim_max);
|
|
|
|
}
|
|
|
|
if (getrlimit(RLIMIT_DATA, &rlim) < 0) {
|
|
|
|
Warn2("getrlimit(RLIMIT_DATA, %p): %s", &rlim, strerror(errno));
|
|
|
|
} else {
|
|
|
|
fprintf(outfile,
|
2014-02-03 10:04:09 +00:00
|
|
|
"data seg size (kbytes) %24"F_rlim_max"%24"F_rlim_max"\n",
|
2008-01-27 12:00:08 +00:00
|
|
|
rlim.rlim_cur, rlim.rlim_max);
|
|
|
|
}
|
|
|
|
if (getrlimit(RLIMIT_STACK, &rlim) < 0) {
|
|
|
|
Warn2("getrlimit(RLIMIT_STACK, %p): %s", &rlim, strerror(errno));
|
|
|
|
} else {
|
|
|
|
fprintf(outfile,
|
2014-02-03 10:04:09 +00:00
|
|
|
"stack size (blocks) %24"F_rlim_max"%24"F_rlim_max"\n",
|
2008-01-27 12:00:08 +00:00
|
|
|
rlim.rlim_cur, rlim.rlim_max);
|
|
|
|
}
|
|
|
|
if (getrlimit(RLIMIT_CORE, &rlim) < 0) {
|
|
|
|
Warn2("getrlimit(RLIMIT_CORE, %p): %s", &rlim, strerror(errno));
|
|
|
|
} else {
|
|
|
|
fprintf(outfile,
|
2014-02-03 10:04:09 +00:00
|
|
|
"core file size (blocks) %24"F_rlim_max"%24"F_rlim_max"\n",
|
2008-01-27 12:00:08 +00:00
|
|
|
rlim.rlim_cur, rlim.rlim_max);
|
|
|
|
}
|
|
|
|
#ifdef RLIMIT_RSS /* Linux, AIX; not Cygwin */
|
|
|
|
if (getrlimit(RLIMIT_RSS, &rlim) < 0) {
|
|
|
|
Warn2("getrlimit(RLIMIT_RSS, %p): %s", &rlim, strerror(errno));
|
|
|
|
} else {
|
|
|
|
fprintf(outfile,
|
2014-02-03 10:04:09 +00:00
|
|
|
"max resident set size %24"F_rlim_max"%24"F_rlim_max"\n",
|
2008-01-27 12:00:08 +00:00
|
|
|
rlim.rlim_cur, rlim.rlim_max);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef RLIMIT_NPROC /* Linux, not AIX, Cygwin */
|
|
|
|
if (getrlimit(RLIMIT_NPROC, &rlim) < 0) {
|
|
|
|
Warn2("getrlimit(RLIMIT_NPROC, %p): %s", &rlim, strerror(errno));
|
|
|
|
} else {
|
|
|
|
fprintf(outfile,
|
2014-02-03 10:04:09 +00:00
|
|
|
"max user processes %24"F_rlim_max"%24"F_rlim_max"\n",
|
2008-01-27 12:00:08 +00:00
|
|
|
rlim.rlim_cur, rlim.rlim_max);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef RLIMIT_NOFILE /* not AIX 4.1 */
|
|
|
|
if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
|
|
|
|
Warn2("getrlimit(RLIMIT_NOFILE, %p): %s", &rlim, strerror(errno));
|
|
|
|
} else {
|
|
|
|
fprintf(outfile,
|
2014-02-03 10:04:09 +00:00
|
|
|
"open files %24"F_rlim_max"%24"F_rlim_max"\n",
|
2008-01-27 12:00:08 +00:00
|
|
|
rlim.rlim_cur, rlim.rlim_max);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef RLIMIT_MEMLOCK /* Linux, not AIX, Cygwin */
|
|
|
|
if (getrlimit(RLIMIT_MEMLOCK, &rlim) < 0) {
|
|
|
|
Warn2("getrlimit(RLIMIT_MEMLOCK, %p): %s", &rlim, strerror(errno));
|
|
|
|
} else {
|
|
|
|
fprintf(outfile,
|
2014-02-03 10:04:09 +00:00
|
|
|
"max locked-in-memory\n address space %24"F_rlim_max"%24"F_rlim_max"\n",
|
2008-01-27 12:00:08 +00:00
|
|
|
rlim.rlim_cur, rlim.rlim_max);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef RLIMIT_AS
|
|
|
|
if (getrlimit(RLIMIT_AS, &rlim) < 0) {
|
|
|
|
Warn2("getrlimit(RLIMIT_AS, %p): %s", &rlim, strerror(errno));
|
|
|
|
} else {
|
|
|
|
fprintf(outfile,
|
2014-02-03 10:04:09 +00:00
|
|
|
"virtual memory (kbytes) %24"F_rlim_max"%24"F_rlim_max"\n",
|
2008-01-27 12:00:08 +00:00
|
|
|
rlim.rlim_cur, rlim.rlim_max);
|
|
|
|
}
|
2020-10-13 18:08:04 +00:00
|
|
|
#endif
|
2023-11-11 16:40:52 +00:00
|
|
|
fputc('\n', outfile);
|
|
|
|
|
2023-10-03 19:02:13 +00:00
|
|
|
}
|
|
|
|
|
2023-11-11 16:40:52 +00:00
|
|
|
#ifdef CC
|
|
|
|
fprintf(outfile, "// CC: "CC"\n");
|
|
|
|
#endif
|
|
|
|
#ifdef __STDC_VERSION__
|
|
|
|
fprintf(outfile, "#define __STDC_VERSION__ %ld\n", __STDC_VERSION__);
|
|
|
|
#endif
|
2020-10-13 18:08:04 +00:00
|
|
|
#ifdef SIZE_MAX
|
2023-11-11 16:40:52 +00:00
|
|
|
fprintf(outfile, "SIZE_MAX = "F_Zu" /* maximum value of size_t */\n", SIZE_MAX);
|
2023-10-03 19:02:13 +00:00
|
|
|
#endif
|
|
|
|
#ifdef P_tmpdir
|
|
|
|
fprintf(outfile, "P_tmpdir = \"%s\"\n", P_tmpdir);
|
|
|
|
#endif
|
|
|
|
#ifdef L_tmpnam
|
|
|
|
fprintf(outfile, "L_tmpnam = %u\n", L_tmpnam);
|
|
|
|
#endif
|
|
|
|
#ifdef TMP_MAX
|
|
|
|
fprintf(outfile, "TMP_MAX = %d\n", TMP_MAX);
|
2023-10-26 16:42:41 +00:00
|
|
|
#endif
|
2023-11-11 16:40:52 +00:00
|
|
|
#ifdef FD_SETSIZE
|
|
|
|
fprintf(outfile, "FD_SETSIZE = %d /* maximum number of FDs for select() */\n", FD_SETSIZE);
|
|
|
|
#endif
|
2023-10-26 16:42:41 +00:00
|
|
|
#ifdef PIPE_BUF
|
2023-10-03 19:02:13 +00:00
|
|
|
fprintf(outfile, "PIPE_BUF = %-24d\n", PIPE_BUF);
|
2008-01-27 12:00:08 +00:00
|
|
|
#endif
|
|
|
|
|
2023-07-21 05:10:38 +00:00
|
|
|
/* Name spaces */
|
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
char link[PATH_MAX];
|
|
|
|
snprintf(path, sizeof(path)-1, "/proc/"F_pid"/ns/net", getpid());
|
|
|
|
if (readlink(path, link, sizeof(link)-1) >= 0) {
|
|
|
|
fprintf(outfile, "Network namespace: %s", link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-27 12:00:08 +00:00
|
|
|
/* file descriptors */
|
|
|
|
|
|
|
|
/* what was this for?? */
|
|
|
|
/*Sleep(1);*/
|
|
|
|
return 0;
|
|
|
|
}
|