/* source: procan.c */ /* Copyright Gerhard Rieger and contributors (see file CHANGES) */ /* 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" #include "sched.h" #include "filan.h" #include /* RLIMIT_CPU ... */ #include /* opendir() readdir() closedir() */ #include "procan.h" /* 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//: \"%s\"\n", cttypath); else fprintf(outfile, "controlling terminal by /proc//: (none)\n"); return 0; } int procan(FILE *outfile) { /*filan(0, outfile);*/ fprintf(outfile, "process id = "F_pid"\n", Getpid()); fprintf(outfile, "process parent id = "F_pid"\n", Getppid()); controlling_term(outfile); 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()); /* 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); } { struct rlimit rlim; fprintf(outfile, "\n/* Resource limits */\n"); fprintf(outfile, "resource current maximum\n"); if (getrlimit(RLIMIT_CPU, &rlim) < 0) { Warn2("getrlimit(RLIMIT_CPU, %p): %s", &rlim, strerror(errno)); } else { fprintf(outfile, "cpu time (seconds) %24"F_rlim_max"%24"F_rlim_max"\n", rlim.rlim_cur, rlim.rlim_max); } if (getrlimit(RLIMIT_FSIZE, &rlim) < 0) { Warn2("getrlimit(RLIMIT_FSIZE, %p): %s", &rlim, strerror(errno)); } else { fprintf(outfile, "file size (blocks) %24"F_rlim_max"%24"F_rlim_max"\n", rlim.rlim_cur, rlim.rlim_max); } if (getrlimit(RLIMIT_DATA, &rlim) < 0) { Warn2("getrlimit(RLIMIT_DATA, %p): %s", &rlim, strerror(errno)); } else { fprintf(outfile, "data seg size (kbytes) %24"F_rlim_max"%24"F_rlim_max"\n", rlim.rlim_cur, rlim.rlim_max); } if (getrlimit(RLIMIT_STACK, &rlim) < 0) { Warn2("getrlimit(RLIMIT_STACK, %p): %s", &rlim, strerror(errno)); } else { fprintf(outfile, "stack size (blocks) %24"F_rlim_max"%24"F_rlim_max"\n", rlim.rlim_cur, rlim.rlim_max); } if (getrlimit(RLIMIT_CORE, &rlim) < 0) { Warn2("getrlimit(RLIMIT_CORE, %p): %s", &rlim, strerror(errno)); } else { fprintf(outfile, "core file size (blocks) %24"F_rlim_max"%24"F_rlim_max"\n", 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, "max resident set size %24"F_rlim_max"%24"F_rlim_max"\n", 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, "max user processes %24"F_rlim_max"%24"F_rlim_max"\n", 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, "open files %24"F_rlim_max"%24"F_rlim_max"\n", 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, "max locked-in-memory\n address space %24"F_rlim_max"%24"F_rlim_max"\n", 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, "virtual memory (kbytes) %24"F_rlim_max"%24"F_rlim_max"\n", rlim.rlim_cur, rlim.rlim_max); } #endif fputc('\n', outfile); } #ifdef CC fprintf(outfile, "// CC: "CC"\n"); #endif #ifdef __STDC_VERSION__ fprintf(outfile, "#define __STDC_VERSION__ %ld\n", __STDC_VERSION__); #endif #ifdef SIZE_MAX fprintf(outfile, "SIZE_MAX = "F_Zu" /* maximum value of size_t */\n", SIZE_MAX); #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); #endif #ifdef FD_SETSIZE fprintf(outfile, "FD_SETSIZE = %d /* maximum number of FDs for select() */\n", FD_SETSIZE); #endif #ifdef PIPE_BUF fprintf(outfile, "PIPE_BUF = %-24d\n", PIPE_BUF); #endif /* 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); } } /* file descriptors */ /* what was this for?? */ /*Sleep(1);*/ return 0; }