>From 980666a94091e9c35d67770fc4adb23c24d6d1ff Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 14 Aug 2019 01:51:24 +0200 Subject: [PATCH 1/2] get_ppid_of: New module. * lib/get_ppid_of.h: New file. * lib/get_ppid_of.c: New file. * modules/get_ppid_of: New file. --- ChangeLog | 7 ++ lib/get_ppid_of.c | 344 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/get_ppid_of.h | 35 ++++++ modules/get_ppid_of | 25 ++++ 4 files changed, 411 insertions(+) create mode 100644 lib/get_ppid_of.c create mode 100644 lib/get_ppid_of.h create mode 100644 modules/get_ppid_of diff --git a/ChangeLog b/ChangeLog index fc4ac17..f7a8d7a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2019-08-13 Bruno Haible + get_ppid_of: New module. + * lib/get_ppid_of.h: New file. + * lib/get_ppid_of.c: New file. + * modules/get_ppid_of: New file. + +2019-08-13 Bruno Haible + libtextstyle-optional tests: Support the NO_COLOR environment variable. * tests/test-libtextstyle.c (main): Do not emit styling when the environment variable NO_COLOR is set. diff --git a/lib/get_ppid_of.c b/lib/get_ppid_of.c new file mode 100644 index 0000000..ef4a5d7 --- /dev/null +++ b/lib/get_ppid_of.c @@ -0,0 +1,344 @@ +/* Determine the parent process of a given process. + Copyright (C) 2019 Free Software Foundation, Inc. + Written by Bruno Haible , 2019. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +/* Specification. */ +#include "get_ppid_of.h" + +#include +#include + +#if defined __linux__ || defined __ANDROID__ || (defined __FreeBSD_kernel__ && !defined __FreeBSD__) || defined __GNU__ || defined __FreeBSD__ || defined __NetBSD__ || defined __minix || defined __sun /* Linux, GNU/kFreeBSD, GNU/Hurd, FreeBSD, NetBSD, Minix, Solaris */ +# include +# include +#endif + +#if defined __OpenBSD__ /* OpenBSD */ +# include /* sysctl, struct kinfo_proc */ +#endif + +#if defined __APPLE__ && defined __MACH__ /* Mac OS X */ +# include +#endif + +#if defined _AIX /* AIX */ +# include +#endif + +#if defined __hpux /* HP-UX */ +# include +# include +# include +#endif + +#if defined __sgi /* IRIX */ +# include +# include +# include +# include +#endif + +#if defined __CYGWIN__ /* Cygwin */ +# define WIN32_LEAN_AND_MEAN +# include /* needed to get 'struct external_pinfo' defined */ +# include +#endif + +#if defined __BEOS__ || defined __HAIKU__ /* BeOS, Haiku */ +# include +#endif + +pid_t +get_ppid_of (pid_t pid) +{ +#if defined __linux__ || defined __ANDROID__ || (defined __FreeBSD_kernel__ && !defined __FreeBSD__) || defined __GNU__ /* Linux, GNU/kFreeBSD, GNU/Hurd */ +/* GNU/kFreeBSD mounts /proc as linprocfs, which looks like a Linux /proc + file system. */ + + /* Read the contents of /proc//status into memory. */ + char filename[6 + 10 + 7 + 1]; + int fd; + + sprintf (filename, "/proc/%u/status", (unsigned int) pid); + fd = open (filename, O_RDONLY); + if (fd >= 0) + { + char buf[4096 + 1]; + ssize_t nread = read (fd, buf, sizeof (buf) - 1); + close (fd); + if (nread >= 0) + { + char *bufend = buf + nread; + char *p; + + /* NUL-terminate the buffer. */ + *bufend = '\0'; + + /* Search for a line that starts with "PPid:". */ + for (p = buf;;) + { + if (bufend - p >= 5 && memcmp (p, "PPid:", 5) == 0) + { + unsigned int ppid = 0; + if (sscanf (p + 5, "%u", &ppid) > 0) + return ppid; + } + p = strchr (p, '\n'); + if (p != NULL) + p++; + else + break; + } + } + } + +#endif + +#if defined __FreeBSD__ || defined __NetBSD__ /* FreeBSD, NetBSD */ + + /* Read the contents of /proc//status into memory. */ + char filename[6 + 10 + 7 + 1]; + int fd; + + sprintf (filename, "/proc/%u/status", (unsigned int) pid); + fd = open (filename, O_RDONLY); + if (fd >= 0) + { + char buf[4096 + 1]; + ssize_t nread = read (fd, buf, sizeof (buf) - 1); + close (fd); + if (nread >= 0) + { + char *bufend = buf + nread; + char *p; + + /* NUL-terminate the buffer. */ + *bufend = '\0'; + + /* Search for the third space-separated field. */ + p = strchr (buf, ' '); + if (p != NULL) + { + p = strchr (p + 1, ' '); + if (p != NULL) + { + unsigned int ppid = 0; + if (sscanf (p + 1, "%u", &ppid) > 0) + return ppid; + } + } + } + } + +#endif + +#if defined __minix /* Minix */ + + /* Read the contents of /proc//psinfo into memory. */ + char filename[6 + 10 + 7 + 1]; + int fd; + + sprintf (filename, "/proc/%u/psinfo", (unsigned int) pid); + fd = open (filename, O_RDONLY); + if (fd >= 0) + { + char buf[4096 + 1]; + ssize_t nread = read (fd, buf, sizeof (buf) - 1); + close (fd); + if (nread >= 0) + { + char *bufend = buf + nread; + int count; + char *p; + + /* NUL-terminate the buffer. */ + *bufend = '\0'; + + /* Search for the 16th space-separated field. */ + p = strchr (buf, ' '); + for (count = 1; p != NULL && count < 15; count++) + p = strchr (p + 1, ' '); + if (p != NULL) + { + unsigned int ppid = 0; + if (sscanf (p + 1, "%u", &ppid) > 0) + return ppid; + } + } + } + +#endif + +#if defined __sun /* Solaris */ + + /* Read the contents of /proc//psinfo into memory. + Alternatively, we could read the contents of /proc//status into + memory. But it contains a lot of information that we don't need. */ + char filename[6 + 10 + 7 + 1]; + int fd; + + sprintf (filename, "/proc/%u/psinfo", (unsigned int) pid); + fd = open (filename, O_RDONLY); + if (fd >= 0) + { + /* The contents is a 'struct psinfo'. But since 'struct psinfo' + has a different size in a 32-bit and a 64-bit environment, we + avoid it. Nevertheless, the size of this contents depends on + whether the process that reads it is 32-bit or 64-bit! */ + #if defined __LP64__ + # define PSINFO_SIZE 416 + #else + # define PSINFO_SIZE 336 + #endif + union { char all[PSINFO_SIZE]; unsigned int header[11]; } buf; + ssize_t nread = read (fd, buf.all, sizeof (buf.all)); + close (fd); + if (nread >= (ssize_t) sizeof (buf.header)) + return buf.header[3]; + } + +#endif + +#if defined __OpenBSD__ /* OpenBSD */ + + /* Documentation: https://man.openbsd.org/sysctl.2 */ + int info_path[] = + { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid, sizeof (struct kinfo_proc), 1 }; + struct kinfo_proc info; + size_t len; + + len = sizeof (info); + if (sysctl (info_path, 6, &info, &len, NULL, 0) >= 0 && len == sizeof (info)) + return info.p_ppid; + +#endif + +#if defined __APPLE__ && defined __MACH__ /* Mac OS X */ + +# if defined PROC_PIDT_SHORTBSDINFO + struct proc_bsdshortinfo info; + + if (proc_pidinfo (pid, PROC_PIDT_SHORTBSDINFO, 0, &info, sizeof (info)) + == sizeof (info)) + return info.pbsi_ppid; +# else + /* Note: The second part of 'struct proc_bsdinfo' differs in size between + 32-bit and 64-bit environments, and the kernel of Mac OS X 10.5 knows + only about the 32-bit 'struct proc_bsdinfo'. Fortunately all the info + we need is in the first part, which is the same in 32-bit and 64-bit. */ + struct proc_bsdinfo info; + + if (proc_pidinfo (pid, PROC_PIDTBSDINFO, 0, &info, 128) == 128) + return info.pbi_ppid; +# endif + +#endif + +#if defined _AIX /* AIX */ + + /* Reference: https://www.ibm.com/support/knowledgecenter/en/ssw_aix_61/com.ibm.aix.basetrf1/getprocs.htm + */ + struct procentry64 procs; + if (getprocs64 (&procs, sizeof procs, NULL, 0, &pid, 1) > 0) + return procs.pi_ppid; + +#endif + +#if defined __hpux /* HP-UX */ + + struct pst_status status; + if (pstat_getproc (&status, sizeof status, 0, pid) > 0) + return status.pst_ppid; + else + { +# if !defined __LP64__ + /* Support for 32-bit programs running in 64-bit HP-UX. + The documented way to do this is to use the same source code + as above, but in a compilation unit where '#define _PSTAT64 1' + is in effect. I prefer a single compilation unit; the struct + size and the offsets are not going to change. */ + char status64[1216]; + if (__pstat_getproc64 (status64, sizeof status64, 0, pid) > 0) + return *(unsigned long long *)(status64 + 24); +# endif + } + +#endif + +#if defined __sgi /* IRIX */ + + char filename[12 + 10 + 1]; + int fd; + + sprintf (filename, "/proc/pinfo/%u", pid); + fd = open (filename, O_RDONLY); + if (0 <= fd) + { + prpsinfo_t buf; + int ioctl_ok = 0 <= ioctl (fd, PIOCPSINFO, &buf); + close (fd); + if (ioctl_ok) + return buf.pr_ppid; + } + +#endif + +#if defined __CYGWIN__ /* Cygwin */ + + struct external_pinfo *info = + (struct external_pinfo *) cygwin_internal (CW_GETPINFO, pid); + if (info != NULL) + return info->ppid; + +#endif + +#if defined __BEOS__ || defined __HAIKU__ /* BeOS, Haiku */ + + if (pid == getpid ()) + return getppid (); + +#endif + + return 0; +} + +#ifdef TEST + +#include +#include + +/* Usage: ./a.out + or: ./a.out PID + */ +int +main (int argc, char *argv[]) +{ + char *arg = argv[1]; + pid_t pid = (arg != NULL ? atoi (arg) : getpid ()); + pid_t parent = get_ppid_of (pid); + printf ("PID=%lu PPID=%lu\n", (unsigned long) pid, (unsigned long) parent); + return 0; +} + +/* + * Local Variables: + * compile-command: "gcc -ggdb -DTEST -Wall -I.. get_ppid_of.c" + * End: + */ + +#endif diff --git a/lib/get_ppid_of.h b/lib/get_ppid_of.h new file mode 100644 index 0000000..c757dfb --- /dev/null +++ b/lib/get_ppid_of.h @@ -0,0 +1,35 @@ +/* Determine the parent process of a given process. + Copyright (C) 2019 Free Software Foundation, Inc. + Written by Bruno Haible , 2019. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef _GET_PPID_OF_H +#define _GET_PPID_OF_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Returns the process id of the parent process of the given process, + or 0 if it cannot be determined. */ +extern pid_t get_ppid_of (pid_t pid); + +#ifdef __cplusplus +} +#endif + +#endif /* _GET_PPID_OF_H */ diff --git a/modules/get_ppid_of b/modules/get_ppid_of new file mode 100644 index 0000000..4f2cad1 --- /dev/null +++ b/modules/get_ppid_of @@ -0,0 +1,25 @@ +Description: +Determine the parent process of a given process. + +Files: +lib/get_ppid_of.h +lib/get_ppid_of.c + +Depends-on: +extensions +sys_types +unistd + +configure.ac: + +Makefile.am: +lib_SOURCES += get_ppid_of.h get_ppid_of.c + +Include: +"get_ppid_of.h" + +License: +LGPL + +Maintainer: +all -- 2.7.4