1 /* Determine the parent process of a given process.
2 Copyright (C) 2019-2020 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2019.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program 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 General Public License for more details.
15 You should have received a copy of the GNU 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 __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 */
39 #if defined _AIX /* AIX */
40 # include <procinfo.h>
43 #if defined __hpux /* HP-UX */
45 # include <sys/param.h>
46 # include <sys/pstat.h>
49 #if defined __sgi /* IRIX */
52 # include <sys/procfs.h>
55 #if defined __CYGWIN__ /* Cygwin */
56 # define WIN32_LEAN_AND_MEAN
57 # include <windows.h> /* needed to get 'struct external_pinfo' defined */
58 # include <sys/cygwin.h>
61 #if defined __BEOS__ || defined __HAIKU__ /* BeOS, Haiku */
66 get_ppid_of (pid_t pid
)
68 #if defined __linux__ || defined __ANDROID__ || (defined __FreeBSD_kernel__ && !defined __FreeBSD__) || defined __GNU__ /* Linux, GNU/kFreeBSD, GNU/Hurd */
69 /* GNU/kFreeBSD mounts /proc as linprocfs, which looks like a Linux /proc
72 /* Read the contents of /proc/<pid>/status into memory. */
73 char filename
[6 + 10 + 7 + 1];
76 sprintf (filename
, "/proc/%u/status", (unsigned int) pid
);
77 fd
= open (filename
, O_RDONLY
| O_CLOEXEC
);
81 ssize_t nread
= read (fd
, buf
, sizeof (buf
) - 1);
85 char *bufend
= buf
+ nread
;
88 /* NUL-terminate the buffer. */
91 /* Search for a line that starts with "PPid:". */
94 if (bufend
- p
>= 5 && memcmp (p
, "PPid:", 5) == 0)
96 unsigned int ppid
= 0;
97 if (sscanf (p
+ 5, "%u", &ppid
) > 0)
100 p
= strchr (p
, '\n');
111 #if defined __FreeBSD__ || defined __NetBSD__ /* FreeBSD, NetBSD */
113 /* Read the contents of /proc/<pid>/status into memory. */
114 char filename
[6 + 10 + 7 + 1];
117 sprintf (filename
, "/proc/%u/status", (unsigned int) pid
);
118 fd
= open (filename
, O_RDONLY
| O_CLOEXEC
);
122 ssize_t nread
= read (fd
, buf
, sizeof (buf
) - 1);
128 /* NUL-terminate the buffer. */
131 /* Search for the third space-separated field. */
132 p
= strchr (buf
, ' ');
135 p
= strchr (p
+ 1, ' ');
138 unsigned int ppid
= 0;
139 if (sscanf (p
+ 1, "%u", &ppid
) > 0)
148 #if defined __minix /* Minix */
150 /* Read the contents of /proc/<pid>/psinfo into memory. */
151 char filename
[6 + 10 + 7 + 1];
154 sprintf (filename
, "/proc/%u/psinfo", (unsigned int) pid
);
155 fd
= open (filename
, O_RDONLY
| O_CLOEXEC
);
159 ssize_t nread
= read (fd
, buf
, sizeof (buf
) - 1);
166 /* NUL-terminate the buffer. */
169 /* Search for the 16th space-separated field. */
170 p
= strchr (buf
, ' ');
171 for (count
= 1; p
!= NULL
&& count
< 15; count
++)
172 p
= strchr (p
+ 1, ' ');
175 unsigned int ppid
= 0;
176 if (sscanf (p
+ 1, "%u", &ppid
) > 0)
184 #if defined __sun /* Solaris */
186 /* Read the contents of /proc/<pid>/psinfo into memory.
187 Alternatively, we could read the contents of /proc/<pid>/status into
188 memory. But it contains a lot of information that we don't need. */
189 char filename
[6 + 10 + 7 + 1];
192 sprintf (filename
, "/proc/%u/psinfo", (unsigned int) pid
);
193 fd
= open (filename
, O_RDONLY
| O_CLOEXEC
);
196 /* The contents is a 'struct psinfo'. But since 'struct psinfo'
197 has a different size in a 32-bit and a 64-bit environment, we
198 avoid it. Nevertheless, the size of this contents depends on
199 whether the process that reads it is 32-bit or 64-bit! */
201 # define PSINFO_SIZE 416
203 # define PSINFO_SIZE 336
205 union { char all
[PSINFO_SIZE
]; unsigned int header
[11]; } buf
;
206 ssize_t nread
= read (fd
, buf
.all
, sizeof (buf
.all
));
208 if (nread
>= (ssize_t
) sizeof (buf
.header
))
209 return buf
.header
[3];
214 #if defined __OpenBSD__ /* OpenBSD */
216 /* Documentation: https://man.openbsd.org/sysctl.2 */
218 { CTL_KERN
, KERN_PROC
, KERN_PROC_PID
, pid
, sizeof (struct kinfo_proc
), 1 };
219 struct kinfo_proc info
;
223 if (sysctl (info_path
, 6, &info
, &len
, NULL
, 0) >= 0 && len
== sizeof (info
))
228 #if defined __APPLE__ && defined __MACH__ /* Mac OS X */
230 # if defined PROC_PIDT_SHORTBSDINFO
231 struct proc_bsdshortinfo info
;
233 if (proc_pidinfo (pid
, PROC_PIDT_SHORTBSDINFO
, 0, &info
, sizeof (info
))
235 return info
.pbsi_ppid
;
237 /* Note: The second part of 'struct proc_bsdinfo' differs in size between
238 32-bit and 64-bit environments, and the kernel of Mac OS X 10.5 knows
239 only about the 32-bit 'struct proc_bsdinfo'. Fortunately all the info
240 we need is in the first part, which is the same in 32-bit and 64-bit. */
241 struct proc_bsdinfo info
;
243 if (proc_pidinfo (pid
, PROC_PIDTBSDINFO
, 0, &info
, 128) == 128)
244 return info
.pbi_ppid
;
249 #if defined _AIX /* AIX */
251 /* Reference: https://www.ibm.com/support/knowledgecenter/en/ssw_aix_61/com.ibm.aix.basetrf1/getprocs.htm
253 struct procentry64 procs
;
254 if (getprocs64 (&procs
, sizeof procs
, NULL
, 0, &pid
, 1) > 0)
255 return procs
.pi_ppid
;
259 #if defined __hpux /* HP-UX */
261 struct pst_status status
;
262 if (pstat_getproc (&status
, sizeof status
, 0, pid
) > 0)
263 return status
.pst_ppid
;
266 # if !defined __LP64__
267 /* Support for 32-bit programs running in 64-bit HP-UX.
268 The documented way to do this is to use the same source code
269 as above, but in a compilation unit where '#define _PSTAT64 1'
270 is in effect. I prefer a single compilation unit; the struct
271 size and the offsets are not going to change. */
273 if (__pstat_getproc64 (status64
, sizeof status64
, 0, pid
) > 0)
274 return *(unsigned long long *)(status64
+ 24);
280 #if defined __sgi /* IRIX */
282 char filename
[12 + 10 + 1];
285 sprintf (filename
, "/proc/pinfo/%u", pid
);
286 fd
= open (filename
, O_RDONLY
| O_CLOEXEC
);
290 int ioctl_ok
= 0 <= ioctl (fd
, PIOCPSINFO
, &buf
);
298 #if defined __CYGWIN__ /* Cygwin */
300 struct external_pinfo
*info
=
301 (struct external_pinfo
*) cygwin_internal (CW_GETPINFO
, pid
);
307 #if defined __BEOS__ || defined __HAIKU__ /* BeOS, Haiku */
309 if (pid
== getpid ())
326 main (int argc
, char *argv
[])
329 pid_t pid
= (arg
!= NULL
? atoi (arg
) : getpid ());
330 pid_t parent
= get_ppid_of (pid
);
331 printf ("PID=%lu PPID=%lu\n", (unsigned long) pid
, (unsigned long) parent
);
337 * compile-command: "gcc -ggdb -DTEST -Wall -I.. get_ppid_of.c"