1 /* Determine the parent process of a given process.
2 Copyright (C) 2019-2024 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2019.
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation, either version 3 of the
8 License, or (at your option) any later version.
10 This file is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
21 #include "get_ppid_of.h"
26 #if defined __linux__ || defined __ANDROID__ || (defined __FreeBSD_kernel__ && !defined __FreeBSD__) || defined __GNU__ || defined __FreeBSD__ || defined __DragonFly__ || defined __NetBSD__ || defined __minix || defined __sun /* Linux, GNU/kFreeBSD, GNU/Hurd, FreeBSD, NetBSD, Minix, Solaris */
31 #if defined __OpenBSD__ /* OpenBSD */
32 # include <sys/sysctl.h> /* sysctl, struct kinfo_proc */
35 #if defined __APPLE__ && defined __MACH__ /* Mac OS X */
36 /* Get MAC_OS_X_VERSION_MIN_REQUIRED, MAC_OS_X_VERSION_MAX_ALLOWED.
37 The version at runtime satisfies
38 MAC_OS_X_VERSION_MIN_REQUIRED <= version <= MAC_OS_X_VERSION_MAX_ALLOWED. */
39 # include <AvailabilityMacros.h>
40 # if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
42 # if MAC_OS_X_VERSION_MIN_REQUIRED < 1050
43 /* Mac OS X versions < 10.5 don't have this function. Therefore declare it as
44 weak, in order to avoid a runtime error when the binaries are run on these
46 extern int proc_pidinfo (int, int, uint64_t, void *, int) WEAK_IMPORT_ATTRIBUTE
;
51 #if defined _AIX /* AIX */
52 # include <procinfo.h>
55 #if defined __hpux /* HP-UX */
57 # include <sys/param.h>
58 # include <sys/pstat.h>
61 #if defined __sgi /* IRIX */
64 # include <sys/procfs.h>
67 #if defined __CYGWIN__ /* Cygwin */
68 # define WIN32_LEAN_AND_MEAN
69 # include <windows.h> /* needed to get 'struct external_pinfo' defined */
70 # include <sys/cygwin.h>
73 #if defined __BEOS__ || defined __HAIKU__ /* BeOS, Haiku */
78 get_ppid_of (pid_t pid
)
80 #if defined __linux__ || defined __ANDROID__ || (defined __FreeBSD_kernel__ && !defined __FreeBSD__) || defined __GNU__ /* Linux, GNU/kFreeBSD, GNU/Hurd */
81 /* GNU/kFreeBSD mounts /proc as linprocfs, which looks like a Linux /proc
84 /* Read the contents of /proc/<pid>/status into memory. */
85 char filename
[6 + 10 + 7 + 1];
88 sprintf (filename
, "/proc/%u/status", (unsigned int) pid
);
89 fd
= open (filename
, O_RDONLY
| O_CLOEXEC
);
93 ssize_t nread
= read (fd
, buf
, sizeof (buf
) - 1);
97 char *bufend
= buf
+ nread
;
100 /* NUL-terminate the buffer. */
103 /* Search for a line that starts with "PPid:". */
106 if (bufend
- p
>= 5 && memcmp (p
, "PPid:", 5) == 0)
108 unsigned int ppid
= 0;
109 if (sscanf (p
+ 5, "%u", &ppid
) > 0)
112 p
= strchr (p
, '\n');
123 #if defined __FreeBSD__ || defined __DragonFly__ || defined __NetBSD__ /* FreeBSD, NetBSD */
125 /* Read the contents of /proc/<pid>/status into memory. */
126 char filename
[6 + 10 + 7 + 1];
129 sprintf (filename
, "/proc/%u/status", (unsigned int) pid
);
130 fd
= open (filename
, O_RDONLY
| O_CLOEXEC
);
134 ssize_t nread
= read (fd
, buf
, sizeof (buf
) - 1);
140 /* NUL-terminate the buffer. */
143 /* Search for the third space-separated field. */
144 p
= strchr (buf
, ' ');
147 p
= strchr (p
+ 1, ' ');
150 unsigned int ppid
= 0;
151 if (sscanf (p
+ 1, "%u", &ppid
) > 0)
160 #if defined __minix /* Minix */
162 /* Read the contents of /proc/<pid>/psinfo into memory. */
163 char filename
[6 + 10 + 7 + 1];
166 sprintf (filename
, "/proc/%u/psinfo", (unsigned int) pid
);
167 fd
= open (filename
, O_RDONLY
| O_CLOEXEC
);
171 ssize_t nread
= read (fd
, buf
, sizeof (buf
) - 1);
178 /* NUL-terminate the buffer. */
181 /* Search for the 16th space-separated field. */
182 p
= strchr (buf
, ' ');
183 for (count
= 1; p
!= NULL
&& count
< 15; count
++)
184 p
= strchr (p
+ 1, ' ');
187 unsigned int ppid
= 0;
188 if (sscanf (p
+ 1, "%u", &ppid
) > 0)
196 #if defined __sun /* Solaris */
198 /* Read the contents of /proc/<pid>/psinfo into memory.
199 Alternatively, we could read the contents of /proc/<pid>/status into
200 memory. But it contains a lot of information that we don't need. */
201 char filename
[6 + 10 + 7 + 1];
204 sprintf (filename
, "/proc/%u/psinfo", (unsigned int) pid
);
205 fd
= open (filename
, O_RDONLY
| O_CLOEXEC
);
208 /* The contents is a 'struct psinfo'. But since 'struct psinfo'
209 has a different size in a 32-bit and a 64-bit environment, we
210 avoid it. Nevertheless, the size of this contents depends on
211 whether the process that reads it is 32-bit or 64-bit! */
213 # define PSINFO_SIZE 416
215 # define PSINFO_SIZE 336
217 union { char all
[PSINFO_SIZE
]; unsigned int header
[11]; } buf
;
218 ssize_t nread
= read (fd
, buf
.all
, sizeof (buf
.all
));
220 if (nread
>= (ssize_t
) sizeof (buf
.header
))
221 return buf
.header
[3];
226 #if defined __OpenBSD__ /* OpenBSD */
228 /* Documentation: https://man.openbsd.org/sysctl.2 */
230 { CTL_KERN
, KERN_PROC
, KERN_PROC_PID
, pid
, sizeof (struct kinfo_proc
), 1 };
231 struct kinfo_proc info
;
235 if (sysctl (info_path
, 6, &info
, &len
, NULL
, 0) >= 0 && len
== sizeof (info
))
240 #if defined __APPLE__ && defined __MACH__ /* Mac OS X */
241 # if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
243 /* Mac OS X >= 10.7 has PROC_PIDT_SHORTBSDINFO. */
244 # if defined PROC_PIDT_SHORTBSDINFO
245 # if MAC_OS_X_VERSION_MIN_REQUIRED < 1050
246 if (proc_pidinfo
!= NULL
) /* at runtime Mac OS X >= 10.5 ? */
249 struct proc_bsdshortinfo info
;
251 if (proc_pidinfo (pid
, PROC_PIDT_SHORTBSDINFO
, 0, &info
, sizeof (info
))
253 return info
.pbsi_ppid
;
257 # if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
258 /* For older versions, use PROC_PIDTBSDINFO instead. */
259 /* Note: The second part of 'struct proc_bsdinfo' differs in size between
260 32-bit and 64-bit environments, and the kernel of Mac OS X 10.5 knows
261 only about the 32-bit 'struct proc_bsdinfo'. Fortunately all the info
262 we need is in the first part, which is the same in 32-bit and 64-bit. */
263 # if MAC_OS_X_VERSION_MIN_REQUIRED < 1050
264 if (proc_pidinfo
!= NULL
) /* at runtime Mac OS X >= 10.5 ? */
267 struct proc_bsdinfo info
;
269 if (proc_pidinfo (pid
, PROC_PIDTBSDINFO
, 0, &info
, 128) == 128)
270 return info
.pbi_ppid
;
277 #if defined _AIX /* AIX */
279 /* Reference: https://www.ibm.com/support/knowledgecenter/en/ssw_aix_61/com.ibm.aix.basetrf1/getprocs.htm
281 struct procentry64 procs
;
282 if (getprocs64 (&procs
, sizeof procs
, NULL
, 0, &pid
, 1) > 0)
283 return procs
.pi_ppid
;
287 #if defined __hpux /* HP-UX */
289 struct pst_status status
;
290 if (pstat_getproc (&status
, sizeof status
, 0, pid
) > 0)
291 return status
.pst_ppid
;
294 # if !defined __LP64__
295 /* Support for 32-bit programs running in 64-bit HP-UX.
296 The documented way to do this is to use the same source code
297 as above, but in a compilation unit where '#define _PSTAT64 1'
298 is in effect. I prefer a single compilation unit; the struct
299 size and the offsets are not going to change. */
301 if (__pstat_getproc64 (status64
, sizeof status64
, 0, pid
) > 0)
302 return *(unsigned long long *)(status64
+ 24);
308 #if defined __sgi /* IRIX */
310 char filename
[12 + 10 + 1];
313 sprintf (filename
, "/proc/pinfo/%u", pid
);
314 fd
= open (filename
, O_RDONLY
| O_CLOEXEC
);
318 int ioctl_ok
= 0 <= ioctl (fd
, PIOCPSINFO
, &buf
);
326 #if defined __CYGWIN__ /* Cygwin */
328 struct external_pinfo
*info
=
329 (struct external_pinfo
*) cygwin_internal (CW_GETPINFO
, pid
);
335 #if defined __BEOS__ || defined __HAIKU__ /* BeOS, Haiku */
337 if (pid
== getpid ())
354 main (int argc
, char *argv
[])
357 pid_t pid
= (arg
!= NULL
? atoi (arg
) : getpid ());
358 pid_t parent
= get_ppid_of (pid
);
359 printf ("PID=%lu PPID=%lu\n", (unsigned long) pid
, (unsigned long) parent
);
365 * compile-command: "gcc -ggdb -DTEST -Wall -I.. get_ppid_of.c"