[4/4] linux: Add pidfd_getpid
Checks
Context |
Check |
Description |
dj/TryBot-apply_patch |
success
|
Patch applied to master at the time it was sent
|
dj/TryBot-32bit |
success
|
Build for i686
|
Commit Message
This interface allows to obtain the associated pid ID from the
process file descriptor. It is done by parsing the procps fdinfo
information.
Checked on x86_64-linux-gnu on Linux 4.15 (no CLONE_PID or waitid
support), Linux 5.15 (only clone support), and Linux 5.19 (full
support including clone3).
---
NEWS | 4 +
sysdeps/unix/sysv/linux/Makefile | 2 +
sysdeps/unix/sysv/linux/Versions | 1 +
sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 +
sysdeps/unix/sysv/linux/arc/libc.abilist | 1 +
sysdeps/unix/sysv/linux/arm/be/libc.abilist | 1 +
sysdeps/unix/sysv/linux/arm/le/libc.abilist | 1 +
sysdeps/unix/sysv/linux/csky/libc.abilist | 1 +
sysdeps/unix/sysv/linux/hppa/libc.abilist | 1 +
sysdeps/unix/sysv/linux/i386/libc.abilist | 1 +
sysdeps/unix/sysv/linux/ia64/libc.abilist | 1 +
.../sysv/linux/loongarch/lp64/libc.abilist | 1 +
.../sysv/linux/m68k/coldfire/libc.abilist | 1 +
.../unix/sysv/linux/m68k/m680x0/libc.abilist | 1 +
.../sysv/linux/microblaze/be/libc.abilist | 1 +
.../sysv/linux/microblaze/le/libc.abilist | 1 +
.../sysv/linux/mips/mips32/fpu/libc.abilist | 1 +
.../sysv/linux/mips/mips32/nofpu/libc.abilist | 1 +
.../sysv/linux/mips/mips64/n32/libc.abilist | 1 +
.../sysv/linux/mips/mips64/n64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/nios2/libc.abilist | 1 +
sysdeps/unix/sysv/linux/or1k/libc.abilist | 1 +
sysdeps/unix/sysv/linux/pidfd_getpid.c | 70 +++++++++++++
.../linux/powerpc/powerpc32/fpu/libc.abilist | 1 +
.../powerpc/powerpc32/nofpu/libc.abilist | 1 +
.../linux/powerpc/powerpc64/be/libc.abilist | 1 +
.../linux/powerpc/powerpc64/le/libc.abilist | 1 +
sysdeps/unix/sysv/linux/procutils.c | 99 +++++++++++++++++++
sysdeps/unix/sysv/linux/procutils.h | 37 +++++++
.../unix/sysv/linux/riscv/rv32/libc.abilist | 1 +
.../unix/sysv/linux/riscv/rv64/libc.abilist | 1 +
.../unix/sysv/linux/s390/s390-32/libc.abilist | 1 +
.../unix/sysv/linux/s390/s390-64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/sh/be/libc.abilist | 1 +
sysdeps/unix/sysv/linux/sh/le/libc.abilist | 1 +
.../sysv/linux/sparc/sparc32/libc.abilist | 1 +
.../sysv/linux/sparc/sparc64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/sys/pidfd.h | 4 +
sysdeps/unix/sysv/linux/tst-pidfd.c | 7 ++
.../unix/sysv/linux/x86_64/64/libc.abilist | 1 +
.../unix/sysv/linux/x86_64/x32/libc.abilist | 1 +
42 files changed, 258 insertions(+)
create mode 100644 sysdeps/unix/sysv/linux/pidfd_getpid.c
create mode 100644 sysdeps/unix/sysv/linux/procutils.c
create mode 100644 sysdeps/unix/sysv/linux/procutils.h
Comments
> +parse_fdinfo (const char *l, void *arg)
> +{
> + enum { fieldlen = sizeof ("Pid:") - 1 };
> + if (strncmp (l, "Pid:", fieldlen) != 0)
> + return true;
> +
> + l += fieldlen;
> +
> + char *endp;
> + unsigned long int n = strtoul (l, &endp, 10);
> + if (l == endp || n > INT_MAX)
> + return true;
> +
> + *(pid_t *)arg = n;
> + return false;
> +}
> +
> +pid_t
> +pidfd_getpid (int fd)
> +{
> + if (__glibc_unlikely (fd < 0))
> + {
> + __set_errno (EINVAL);
> + return -1;
> + }
> +
> + char fdinfoname[FDINFO_FILENAME_LEN];
> +
> + char *p = mempcpy (fdinfoname, FDINFO_TO_FILENAME_PREFIX,
> + strlen (FDINFO_TO_FILENAME_PREFIX));
> + *_fitoa_word (fd, p, 10, 0) = '\0';
> +
> + pid_t pid;
> + if (procutils_read_file (fdinfoname, parse_fdinfo, &pid) == -1)
> + return -1;
> +
> + return pid;
Having implemented this parsing by hand across 3 projects, it is great
to see a glibc helper coming.
However, please handle the case of Pid being 0 and -1 explicitly, and
return a recognizable errno. fdinfo listing 0 means the pidfd cannot be
resolved because it's in a separate pid namespace, so something EREMOTE
would suffice. -1 means the process exited, so ESRCH seems like the
right error. The distiction between these cases and other errors is
important to userspace where we do process tracking, like
systemd/dbus/polkit.
> + The CLOSURE should return false if the read should continue, or false
> + if the function should stop.
Did you mean "true if the read should continue"?
> + TEST_COMPARE (pidfd_getpid (INT_MAX), -1);
> + {
> + pid_t querypid = pidfd_getpid (pidfd);
> + TEST_COMPARE (querypid, pid);
> + }
I think it would be a good idea to add a negative test, eg for a
process that exited or so.
(I am not subscribed to the list, so please CC directly if needed)
On 19/04/23 07:29, Luca Boccassi wrote:
>> +parse_fdinfo (const char *l, void *arg)
>> +{
>> + enum { fieldlen = sizeof ("Pid:") - 1 };
>> + if (strncmp (l, "Pid:", fieldlen) != 0)
>> + return true;
>> +
>> + l += fieldlen;
>> +
>> + char *endp;
>> + unsigned long int n = strtoul (l, &endp, 10);
>> + if (l == endp || n > INT_MAX)
>> + return true;
>> +
>> + *(pid_t *)arg = n;
>> + return false;
>> +}
>> +
>> +pid_t
>> +pidfd_getpid (int fd)
>> +{
>> + if (__glibc_unlikely (fd < 0))
>> + {
>> + __set_errno (EINVAL);
>> + return -1;
>> + }
>> +
>> + char fdinfoname[FDINFO_FILENAME_LEN];
>> +
>> + char *p = mempcpy (fdinfoname, FDINFO_TO_FILENAME_PREFIX,
>> + strlen (FDINFO_TO_FILENAME_PREFIX));
>> + *_fitoa_word (fd, p, 10, 0) = '\0';
>> +
>> + pid_t pid;
>> + if (procutils_read_file (fdinfoname, parse_fdinfo, &pid) == -1)
>> + return -1;
>> +
>> + return pid;
>
> Having implemented this parsing by hand across 3 projects, it is great
> to see a glibc helper coming.
>
> However, please handle the case of Pid being 0 and -1 explicitly, and
> return a recognizable errno. fdinfo listing 0 means the pidfd cannot be
> resolved because it's in a separate pid namespace, so something EREMOTE
> would suffice. -1 means the process exited, so ESRCH seems like the
> right error. The distiction between these cases and other errors is
> important to userspace where we do process tracking, like
> systemd/dbus/polkit.
Ok, it should a matter to handle the 'Pid:' as signed. However, I am not
sure if it is really worth to set the errno in cases, since the information
will already available from the function return itself.
>
>> + The CLOSURE should return false if the read should continue, or false
>> + if the function should stop.
>
> Did you mean "true if the read should continue"?
Indeed.
>
>> + TEST_COMPARE (pidfd_getpid (INT_MAX), -1);
>> + {
>> + pid_t querypid = pidfd_getpid (pidfd);
>> + TEST_COMPARE (querypid, pid);
>> + }
>
> I think it would be a good idea to add a negative test, eg for a
> process that exited or so.
Alright, I will add a more comprehensible test.
>
> (I am not subscribed to the list, so please CC directly if needed)
>
On Wed, 19 Apr 2023 at 14:56, Adhemerval Zanella Netto
<adhemerval.zanella@linaro.org> wrote:
> On 19/04/23 07:29, Luca Boccassi wrote:
> >> +parse_fdinfo (const char *l, void *arg)
> >> +{
> >> + enum { fieldlen = sizeof ("Pid:") - 1 };
> >> + if (strncmp (l, "Pid:", fieldlen) != 0)
> >> + return true;
> >> +
> >> + l += fieldlen;
> >> +
> >> + char *endp;
> >> + unsigned long int n = strtoul (l, &endp, 10);
> >> + if (l == endp || n > INT_MAX)
> >> + return true;
> >> +
> >> + *(pid_t *)arg = n;
> >> + return false;
> >> +}
> >> +
> >> +pid_t
> >> +pidfd_getpid (int fd)
> >> +{
> >> + if (__glibc_unlikely (fd < 0))
> >> + {
> >> + __set_errno (EINVAL);
> >> + return -1;
> >> + }
> >> +
> >> + char fdinfoname[FDINFO_FILENAME_LEN];
> >> +
> >> + char *p = mempcpy (fdinfoname, FDINFO_TO_FILENAME_PREFIX,
> >> + strlen (FDINFO_TO_FILENAME_PREFIX));
> >> + *_fitoa_word (fd, p, 10, 0) = '\0';
> >> +
> >> + pid_t pid;
> >> + if (procutils_read_file (fdinfoname, parse_fdinfo, &pid) == -1)
> >> + return -1;
> >> +
> >> + return pid;
> >
> > Having implemented this parsing by hand across 3 projects, it is great
> > to see a glibc helper coming.
> >
> > However, please handle the case of Pid being 0 and -1 explicitly, and
> > return a recognizable errno. fdinfo listing 0 means the pidfd cannot be
> > resolved because it's in a separate pid namespace, so something EREMOTE
> > would suffice. -1 means the process exited, so ESRCH seems like the
> > right error. The distiction between these cases and other errors is
> > important to userspace where we do process tracking, like
> > systemd/dbus/polkit.
>
> Ok, it should a matter to handle the 'Pid:' as signed. However, I am not
> sure if it is really worth to set the errno in cases, since the information
> will already available from the function return itself.
The function returns the pid, so the same information wouldn't be
available. Eg. returning -1 because you can't read proc because of
selinux permissions is different from returning -1 because the process
was reaped and fdinfo contained -1 so it was just passed through. We
need to know this distinction in userspace to handle it properly.
Setting the errno accordingly seems the best way to do that to me.
Kind regards,
Luca Boccassi
On 19/04/23 11:01, Luca Boccassi wrote:
> On Wed, 19 Apr 2023 at 14:56, Adhemerval Zanella Netto
> <adhemerval.zanella@linaro.org> wrote:
>> On 19/04/23 07:29, Luca Boccassi wrote:
>>>> +parse_fdinfo (const char *l, void *arg)
>>>> +{
>>>> + enum { fieldlen = sizeof ("Pid:") - 1 };
>>>> + if (strncmp (l, "Pid:", fieldlen) != 0)
>>>> + return true;
>>>> +
>>>> + l += fieldlen;
>>>> +
>>>> + char *endp;
>>>> + unsigned long int n = strtoul (l, &endp, 10);
>>>> + if (l == endp || n > INT_MAX)
>>>> + return true;
>>>> +
>>>> + *(pid_t *)arg = n;
>>>> + return false;
>>>> +}
>>>> +
>>>> +pid_t
>>>> +pidfd_getpid (int fd)
>>>> +{
>>>> + if (__glibc_unlikely (fd < 0))
>>>> + {
>>>> + __set_errno (EINVAL);
>>>> + return -1;
>>>> + }
>>>> +
>>>> + char fdinfoname[FDINFO_FILENAME_LEN];
>>>> +
>>>> + char *p = mempcpy (fdinfoname, FDINFO_TO_FILENAME_PREFIX,
>>>> + strlen (FDINFO_TO_FILENAME_PREFIX));
>>>> + *_fitoa_word (fd, p, 10, 0) = '\0';
>>>> +
>>>> + pid_t pid;
>>>> + if (procutils_read_file (fdinfoname, parse_fdinfo, &pid) == -1)
>>>> + return -1;
>>>> +
>>>> + return pid;
>>>
>>> Having implemented this parsing by hand across 3 projects, it is great
>>> to see a glibc helper coming.
>>>
>>> However, please handle the case of Pid being 0 and -1 explicitly, and
>>> return a recognizable errno. fdinfo listing 0 means the pidfd cannot be
>>> resolved because it's in a separate pid namespace, so something EREMOTE
>>> would suffice. -1 means the process exited, so ESRCH seems like the
>>> right error. The distiction between these cases and other errors is
>>> important to userspace where we do process tracking, like
>>> systemd/dbus/polkit.
>>
>> Ok, it should a matter to handle the 'Pid:' as signed. However, I am not
>> sure if it is really worth to set the errno in cases, since the information
>> will already available from the function return itself.
>
> The function returns the pid, so the same information wouldn't be
> available. Eg. returning -1 because you can't read proc because of
> selinux permissions is different from returning -1 because the process
> was reaped and fdinfo contained -1 so it was just passed through. We
> need to know this distinction in userspace to handle it properly.
> Setting the errno accordingly seems the best way to do that to me.
I am kind worried where such errors might clash with other open/read/close
used in parsing, but at least it seems ESRCH should not be generated in such
cases. I am still not sure about EREMOTE, maybe we should just map the
pid equal 0 to -1/EREMOTE.
On Wed, 19 Apr 2023 at 15:11, Adhemerval Zanella Netto
<adhemerval.zanella@linaro.org> wrote:
> On 19/04/23 11:01, Luca Boccassi wrote:
> > On Wed, 19 Apr 2023 at 14:56, Adhemerval Zanella Netto
> > <adhemerval.zanella@linaro.org> wrote:
> >> On 19/04/23 07:29, Luca Boccassi wrote:
> >>>> +parse_fdinfo (const char *l, void *arg)
> >>>> +{
> >>>> + enum { fieldlen = sizeof ("Pid:") - 1 };
> >>>> + if (strncmp (l, "Pid:", fieldlen) != 0)
> >>>> + return true;
> >>>> +
> >>>> + l += fieldlen;
> >>>> +
> >>>> + char *endp;
> >>>> + unsigned long int n = strtoul (l, &endp, 10);
> >>>> + if (l == endp || n > INT_MAX)
> >>>> + return true;
> >>>> +
> >>>> + *(pid_t *)arg = n;
> >>>> + return false;
> >>>> +}
> >>>> +
> >>>> +pid_t
> >>>> +pidfd_getpid (int fd)
> >>>> +{
> >>>> + if (__glibc_unlikely (fd < 0))
> >>>> + {
> >>>> + __set_errno (EINVAL);
> >>>> + return -1;
> >>>> + }
> >>>> +
> >>>> + char fdinfoname[FDINFO_FILENAME_LEN];
> >>>> +
> >>>> + char *p = mempcpy (fdinfoname, FDINFO_TO_FILENAME_PREFIX,
> >>>> + strlen (FDINFO_TO_FILENAME_PREFIX));
> >>>> + *_fitoa_word (fd, p, 10, 0) = '\0';
> >>>> +
> >>>> + pid_t pid;
> >>>> + if (procutils_read_file (fdinfoname, parse_fdinfo, &pid) == -1)
> >>>> + return -1;
> >>>> +
> >>>> + return pid;
> >>>
> >>> Having implemented this parsing by hand across 3 projects, it is great
> >>> to see a glibc helper coming.
> >>>
> >>> However, please handle the case of Pid being 0 and -1 explicitly, and
> >>> return a recognizable errno. fdinfo listing 0 means the pidfd cannot be
> >>> resolved because it's in a separate pid namespace, so something EREMOTE
> >>> would suffice. -1 means the process exited, so ESRCH seems like the
> >>> right error. The distiction between these cases and other errors is
> >>> important to userspace where we do process tracking, like
> >>> systemd/dbus/polkit.
> >>
> >> Ok, it should a matter to handle the 'Pid:' as signed. However, I am not
> >> sure if it is really worth to set the errno in cases, since the information
> >> will already available from the function return itself.
> >
> > The function returns the pid, so the same information wouldn't be
> > available. Eg. returning -1 because you can't read proc because of
> > selinux permissions is different from returning -1 because the process
> > was reaped and fdinfo contained -1 so it was just passed through. We
> > need to know this distinction in userspace to handle it properly.
> > Setting the errno accordingly seems the best way to do that to me.
>
> I am kind worried where such errors might clash with other open/read/close
> used in parsing, but at least it seems ESRCH should not be generated in such
> cases. I am still not sure about EREMOTE, maybe we should just map the
> pid equal 0 to -1/EREMOTE.
Yes, -1/EREMOTE makes sense to me.
Kind regards,
Luca Boccassi
@@ -33,6 +33,10 @@ Major new features:
return a process ID, it returns a file descriptor that can be used along
other pidfd functions.
+* On Linux, the pidfd_getpid has been added. It allows to retrieve the
+ process ID associated with process file descriptor created with
+ pid_spawn or pidfd_fork.
+
Deprecated and removed features, and other changes affecting compatibility:
* In the Linux kernel for the hppa/parisc architecture some of the
@@ -441,8 +441,10 @@ sysdep_routines += \
oldglob \
sched_getcpu \
pidfd_fork \
+ pidfd_getpid \
pidfd_spawn \
pidfd_spawnp \
+ procutils \
# sysdep_routines
tests += \
@@ -323,6 +323,7 @@ libc {
}
GLIBC_2.38 {
pidfd_fork;
+ pidfd_getpid;
pidfd_spawn;
pidfd_spawnp;
}
@@ -2666,5 +2666,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
@@ -2775,6 +2775,7 @@ GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 _IO_fprintf F
@@ -2427,5 +2427,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
@@ -547,6 +547,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 _Exit F
@@ -544,6 +544,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 _Exit F
@@ -2703,5 +2703,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
@@ -2652,6 +2652,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 __confstr_chk F
@@ -2836,6 +2836,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 __confstr_chk F
@@ -2601,6 +2601,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 __confstr_chk F
@@ -2187,5 +2187,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
@@ -548,6 +548,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 _Exit F
@@ -2779,6 +2779,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 __confstr_chk F
@@ -2752,5 +2752,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
@@ -2749,5 +2749,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
@@ -2744,6 +2744,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 __confstr_chk F
@@ -2742,6 +2742,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 __confstr_chk F
@@ -2750,6 +2750,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 __confstr_chk F
@@ -2652,6 +2652,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 __confstr_chk F
@@ -2791,5 +2791,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
@@ -2173,5 +2173,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
new file mode 100644
@@ -0,0 +1,70 @@
+/* pidfd_getpid - Get the associated pid from the pid file descriptor.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <_itoa.h>
+#include <errno.h>
+#include <intprops.h>
+#include <procutils.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define FDINFO_TO_FILENAME_PREFIX "/proc/self/fdinfo/"
+
+#define FDINFO_FILENAME_LEN \
+ (sizeof (FDINFO_TO_FILENAME_PREFIX) + INT_STRLEN_BOUND (int))
+
+static bool
+parse_fdinfo (const char *l, void *arg)
+{
+ enum { fieldlen = sizeof ("Pid:") - 1 };
+ if (strncmp (l, "Pid:", fieldlen) != 0)
+ return true;
+
+ l += fieldlen;
+
+ char *endp;
+ unsigned long int n = strtoul (l, &endp, 10);
+ if (l == endp || n > INT_MAX)
+ return true;
+
+ *(pid_t *)arg = n;
+ return false;
+}
+
+pid_t
+pidfd_getpid (int fd)
+{
+ if (__glibc_unlikely (fd < 0))
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ char fdinfoname[FDINFO_FILENAME_LEN];
+
+ char *p = mempcpy (fdinfoname, FDINFO_TO_FILENAME_PREFIX,
+ strlen (FDINFO_TO_FILENAME_PREFIX));
+ *_fitoa_word (fd, p, 10, 0) = '\0';
+
+ pid_t pid;
+ if (procutils_read_file (fdinfoname, parse_fdinfo, &pid) == -1)
+ return -1;
+
+ return pid;
+}
@@ -2818,6 +2818,7 @@ GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 _IO_fprintf F
@@ -2851,6 +2851,7 @@ GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 _IO_fprintf F
@@ -2572,6 +2572,7 @@ GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 _IO_fprintf F
@@ -2886,5 +2886,6 @@ GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
new file mode 100644
@@ -0,0 +1,99 @@
+/* Utilities functions to read/parse Linux procfs and sysfs.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <not-cancel.h>
+#include <procutils.h>
+#include <string.h>
+
+static char *
+next_line (int fd, char *const buffer, char **cp, char **re,
+ char *const buffer_end)
+{
+ char *res = *cp;
+ char *nl = memchr (*cp, '\n', *re - *cp);
+ if (nl == NULL)
+ {
+ if (*cp != buffer)
+ {
+ if (*re == buffer_end)
+ {
+ memmove (buffer, *cp, *re - *cp);
+ *re = buffer + (*re - *cp);
+ *cp = buffer;
+
+ ssize_t n = __read_nocancel (fd, *re, buffer_end - *re);
+ if (n < 0)
+ return NULL;
+
+ *re += n;
+
+ nl = memchr (*cp, '\n', *re - *cp);
+ while (nl == NULL && *re == buffer_end)
+ {
+ /* Truncate too long lines. */
+ *re = buffer + 3 * (buffer_end - buffer) / 4;
+ n = __read_nocancel (fd, *re, buffer_end - *re);
+ if (n < 0)
+ return NULL;
+
+ nl = memchr (*re, '\n', n);
+ **re = '\0';
+ *re += n;
+ }
+ }
+ else
+ nl = memchr (*cp, '\n', *re - *cp);
+
+ res = *cp;
+ }
+
+ if (nl == NULL)
+ nl = *re - 1;
+ }
+
+ *nl = '\0';
+ *cp = nl + 1;
+ assert (*cp <= *re);
+
+ return res == *re ? NULL : res;
+}
+
+int
+procutils_read_file (const char *filename, procutils_closure_t closure,
+ void *arg)
+{
+ enum { buffer_size = 1024 };
+ char buffer[buffer_size];
+ char *buffer_end = buffer + buffer_size;
+ char *cp = buffer_end;
+ char *re = buffer_end;
+
+ int fd = __open64_nocancel (filename, O_RDONLY | O_CLOEXEC);
+ if (fd == -1)
+ return -1;
+
+ char *l;
+ while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL)
+ if (!closure (l, arg))
+ break;
+
+ __close_nocancel_nostatus (fd);
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,37 @@
+/* Utilities functions to read/parse Linux procfs and sysfs.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _PROCUTILS_H
+#define _PROCUTILS_H
+
+#include <stdbool.h>
+
+typedef bool (*procutils_closure_t)(const char *line, void *arg);
+
+/* Open and read the path FILENAME, line per line, and call CLOSURE with
+ argument ARG on each line. The read is done with a static buffer,
+ with non-cancellable calls, and the line is null terminated.
+
+ The CLOSURE should return false if the read should continue, or false
+ if the function should stop.
+
+ It returns 0 in case of success, or -1 otherwise. */
+int procutils_read_file (const char *filename, procutils_closure_t closure,
+ void *arg) attribute_hidden;
+
+#endif
@@ -2429,5 +2429,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
@@ -2629,5 +2629,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
@@ -2816,6 +2816,7 @@ GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 _IO_fprintf F
@@ -2609,6 +2609,7 @@ GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 _IO_fprintf F
@@ -2659,6 +2659,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 __confstr_chk F
@@ -2656,6 +2656,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 __confstr_chk F
@@ -2811,6 +2811,7 @@ GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 _IO_fprintf F
@@ -2624,6 +2624,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 __confstr_chk F
@@ -59,4 +59,8 @@ extern int pidfd_send_signal (int __pidfd, int __sig, siginfo_t *__info,
of the new process to the parent process. */
extern int pidfd_fork (unsigned int __flags) __THROW;
+/* Query the process ID (PID) from process descriptor __FD. Return the PID
+ or -1 in case of an error. */
+extern pid_t pidfd_getpid (int __fd) __THROW;
+
#endif /* _PIDFD_H */
@@ -18,6 +18,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <support/capture_subprocess.h>
#include <support/check.h>
#include <support/process_state.h>
@@ -118,6 +119,12 @@ do_test (void)
int pidfd = pidfd_open (pid, 0);
TEST_VERIFY (pidfd != -1);
+ TEST_COMPARE (pidfd_getpid (INT_MAX), -1);
+ {
+ pid_t querypid = pidfd_getpid (pidfd);
+ TEST_COMPARE (querypid, pid);
+ }
+
/* Wait for first sigtimedwait. */
support_process_state_wait (pid, support_process_state_sleeping);
TEST_COMPARE (pidfd_send_signal (pidfd, SIGUSR1, NULL, 0), 0);
@@ -2575,6 +2575,7 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F
GLIBC_2.4 __confstr_chk F
@@ -2681,5 +2681,6 @@ GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
GLIBC_2.38 pidfd_fork F
+GLIBC_2.38 pidfd_getpid F
GLIBC_2.38 pidfd_spawn F
GLIBC_2.38 pidfd_spawnp F