summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2019-08-14 11:21:37 +0200
committerBruno Haible <bruno@clisp.org>2019-08-14 11:21:50 +0200
commit015fe7c63216234c5aab78f58fcdb072098fee06 (patch)
treeaf2e1ac1212a2ba8439151364eea88a5876779de
parent982bb6cf0704b36d7d655b34e9d4b7617d8137a6 (diff)
downloadgnulib-015fe7c63216234c5aab78f58fcdb072098fee06.tar.gz
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.
-rw-r--r--ChangeLog7
-rw-r--r--lib/get_ppid_of.c341
-rw-r--r--lib/get_ppid_of.h35
-rw-r--r--modules/get_ppid_of25
4 files changed, 408 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 7f0fc1c37e..642f3da1cd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2019-08-14 Bruno Haible <bruno@clisp.org>
+
+ 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 <bruno@clisp.org>
libtextstyle-optional tests: Support the NO_COLOR environment variable.
diff --git a/lib/get_ppid_of.c b/lib/get_ppid_of.c
new file mode 100644
index 0000000000..01c442cbf1
--- /dev/null
+++ b/lib/get_ppid_of.c
@@ -0,0 +1,341 @@
+/* Determine the parent process of a given process.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include "get_ppid_of.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#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 <fcntl.h>
+# include <unistd.h>
+#endif
+
+#if defined __OpenBSD__ /* OpenBSD */
+# include <sys/sysctl.h> /* sysctl, struct kinfo_proc */
+#endif
+
+#if defined __APPLE__ && defined __MACH__ /* Mac OS X */
+# include <libproc.h>
+#endif
+
+#if defined _AIX /* AIX */
+# include <procinfo.h>
+#endif
+
+#if defined __hpux /* HP-UX */
+# include <unistd.h>
+# include <sys/param.h>
+# include <sys/pstat.h>
+#endif
+
+#if defined __sgi /* IRIX */
+# include <unistd.h>
+# include <fcntl.h>
+# include <sys/procfs.h>
+#endif
+
+#if defined __CYGWIN__ /* Cygwin */
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h> /* needed to get 'struct external_pinfo' defined */
+# include <sys/cygwin.h>
+#endif
+
+#if defined __BEOS__ || defined __HAIKU__ /* BeOS, Haiku */
+# include <unistd.h>
+#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/<pid>/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/<pid>/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 *p;
+
+ /* NUL-terminate the buffer. */
+ buf[nread] = '\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/<pid>/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 *p;
+ int count;
+
+ /* NUL-terminate the buffer. */
+ buf[nread] = '\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/<pid>/psinfo into memory.
+ Alternatively, we could read the contents of /proc/<pid>/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 <stdlib.h>
+#include <unistd.h>
+
+/* 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 0000000000..c757dfb643
--- /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 <bruno@clisp.org>, 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 <https://www.gnu.org/licenses/>. */
+
+#ifndef _GET_PPID_OF_H
+#define _GET_PPID_OF_H
+
+#include <sys/types.h>
+
+#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 0000000000..4f2cad1b2c
--- /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