mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-26 23:10:06 +00:00
linux: Add pidfd_getpid
This interface allows to obtain the associated process ID from the process file descriptor. It is done by parsing the procps fdinfo information. Its prototype is: pid_t pidfd_getpid (int fd) It returns the associated pid or -1 in case of an error and sets the errno accordingly. The possible errno values are those from open, read, and close (used on procps parsing), along with: - EBADF if the FD is negative, does not have a PID associated, or if the fdinfo fields contain a value larger than pid_t. - EREMOTE if the PID is in a separate namespace. - ESRCH if the process is already terminated. Checked on x86_64-linux-gnu on Linux 4.15 (no CLONE_PIDFD or waitid support), Linux 5.4 (full support), and Linux 6.2. Reviewed-by: Florian Weimer <fweimer@redhat.com>
This commit is contained in:
parent
0d6f9f6265
commit
e7190fc73d
4
NEWS
4
NEWS
@ -27,6 +27,10 @@ Major new features:
|
||||
The pidfd functionality avoids the issue of PID reuse with the traditional
|
||||
posix_spawn interface.
|
||||
|
||||
* On Linux, the pidfd_getpid function has been added. It allows retrieving
|
||||
the process ID associated with the process file descriptor created by
|
||||
pid_spawn, fork_np, or pidfd_open.
|
||||
|
||||
Deprecated and removed features, and other changes affecting compatibility:
|
||||
|
||||
[Add deprecations, removals and changes affecting compatibility here]
|
||||
|
@ -33,6 +33,7 @@ primitive functions to do each step individually instead.
|
||||
* Process Creation Concepts:: An overview of the hard way to do it.
|
||||
* Process Identification:: How to get the process ID of a process.
|
||||
* Creating a Process:: How to fork a child process.
|
||||
* Querying a Process:: How to query a child process.
|
||||
* Executing a File:: How to make a process execute another program.
|
||||
* Process Completion:: How to tell when a child process has completed.
|
||||
* Process Completion Status:: How to interpret the status value
|
||||
@ -362,6 +363,43 @@ the proper precautions for using @code{vfork}, your program will still
|
||||
work even if the system uses @code{fork} instead.
|
||||
@end deftypefun
|
||||
|
||||
@node Querying a Process
|
||||
@section Querying a Process
|
||||
|
||||
The file descriptor returned by the @code{pidfd_fork} function can be used to
|
||||
query process extra information.
|
||||
|
||||
@deftypefun pid_t pidfd_getpid (int @var{fd})
|
||||
@standards{GNU, sys/pidfd.h}
|
||||
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
|
||||
|
||||
The @code{pidfd_getpid} function retrieves the process ID associated with process
|
||||
file descriptor created with @code{pid_spawn}, @code{pidfd_fork}, or
|
||||
@code{pidfd_open}.
|
||||
|
||||
If the operation fails, @code{pidfd_getpid} return @code{-1} and the following
|
||||
@code{errno} error conditionas are defined:
|
||||
|
||||
@table @code
|
||||
@item EBADF
|
||||
The input file descriptor is invalid, does not have a pidfd associated, or an
|
||||
error has occurred parsing the kernel data.
|
||||
@item EREMOTE
|
||||
There is no process ID to denote the process in the current namespace.
|
||||
@item ESRCH
|
||||
The process for which the file descriptor refers to is terminated.
|
||||
@item ENOENT
|
||||
The procfs is not mounted.
|
||||
@item ENFILE.
|
||||
Too many open files in system (@code{pidfd_open} tries to open a procfs file and
|
||||
read its contents).
|
||||
@item ENOMEM
|
||||
Insufficient kernel memory was available.
|
||||
@end table
|
||||
|
||||
This function is specific to Linux.
|
||||
@end deftypefun
|
||||
|
||||
@node Executing a File
|
||||
@section Executing a File
|
||||
@cindex executing a file
|
||||
|
@ -213,6 +213,7 @@ tests += \
|
||||
tst-ofdlocks \
|
||||
tst-personality \
|
||||
tst-pidfd \
|
||||
tst-pidfd_getpid \
|
||||
tst-pkey \
|
||||
tst-ppoll \
|
||||
tst-prctl \
|
||||
@ -493,8 +494,10 @@ sysdep_headers += \
|
||||
sysdep_routines += \
|
||||
getcpu \
|
||||
oldglob \
|
||||
pidfd_getpid \
|
||||
pidfd_spawn \
|
||||
pidfd_spawnp \
|
||||
procutils \
|
||||
sched_getcpu \
|
||||
spawnattr_getcgroup_np \
|
||||
spawnattr_setcgroup_np \
|
||||
|
@ -322,6 +322,7 @@ libc {
|
||||
%endif
|
||||
}
|
||||
GLIBC_2.39 {
|
||||
pidfd_getpid;
|
||||
pidfd_spawn;
|
||||
pidfd_spawnp;
|
||||
posix_spawnattr_getcgroup_np;
|
||||
|
@ -2673,6 +2673,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2782,6 +2782,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2434,6 +2434,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -554,6 +554,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -551,6 +551,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2710,6 +2710,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2659,6 +2659,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2843,6 +2843,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2608,6 +2608,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2194,6 +2194,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -555,6 +555,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2786,6 +2786,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2759,6 +2759,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2756,6 +2756,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2751,6 +2751,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2749,6 +2749,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2757,6 +2757,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2659,6 +2659,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2798,6 +2798,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2180,6 +2180,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
126
sysdeps/unix/sysv/linux/pidfd_getpid.c
Normal file
126
sysdeps/unix/sysv/linux/pidfd_getpid.c
Normal file
@ -0,0 +1,126 @@
|
||||
/* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sysdep.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define FDINFO_TO_FILENAME_PREFIX "/proc/self/fdinfo/"
|
||||
|
||||
#define FDINFO_FILENAME_LEN \
|
||||
(sizeof (FDINFO_TO_FILENAME_PREFIX) + INT_STRLEN_BOUND (int))
|
||||
|
||||
struct parse_fdinfo_t
|
||||
{
|
||||
bool found;
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
/* Parse the PID field in the fdinfo entry, if existent. Avoid strtol or
|
||||
similar to not be locale dependent. */
|
||||
static int
|
||||
parse_fdinfo (const char *l, void *arg)
|
||||
{
|
||||
enum { fieldlen = sizeof ("Pid:") - 1 };
|
||||
if (strncmp (l, "Pid:", fieldlen) != 0)
|
||||
return 0;
|
||||
|
||||
l += fieldlen;
|
||||
|
||||
/* Skip leading spaces. */
|
||||
while (*l == ' ' || (unsigned int) (*l) -'\t' < 5)
|
||||
l++;
|
||||
|
||||
bool neg = false;
|
||||
switch (*l)
|
||||
{
|
||||
case '-':
|
||||
neg = true;
|
||||
l++;
|
||||
break;
|
||||
case '+':
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*l == '\0')
|
||||
return 0;
|
||||
|
||||
int n = 0;
|
||||
while (*l != '\0')
|
||||
{
|
||||
/* Check if '*l' is a digit. */
|
||||
if ('0' > *l || *l > '9')
|
||||
return -1;
|
||||
|
||||
/* Ignore invalid large values. */
|
||||
if (INT_MULTIPLY_WRAPV (10, n, &n)
|
||||
|| INT_ADD_WRAPV (n, *l++ - '0', &n))
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* -1 indicates that the process is terminated. */
|
||||
if (neg && n != 1)
|
||||
return -1;
|
||||
|
||||
struct parse_fdinfo_t *fdinfo = arg;
|
||||
fdinfo->pid = neg ? -n : n;
|
||||
fdinfo->found = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
pid_t
|
||||
pidfd_getpid (int fd)
|
||||
{
|
||||
if (__glibc_unlikely (fd < 0))
|
||||
{
|
||||
__set_errno (EBADF);
|
||||
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';
|
||||
|
||||
struct parse_fdinfo_t fdinfo = { .found = false, .pid = -1 };
|
||||
if (!procutils_read_file (fdinfoname, parse_fdinfo, &fdinfo))
|
||||
/* The fdinfo contains an invalid 'Pid:' value. */
|
||||
return INLINE_SYSCALL_ERROR_RETURN_VALUE (EBADF);
|
||||
|
||||
/* The FD does not have a 'Pid:' entry associated. */
|
||||
if (!fdinfo.found)
|
||||
return INLINE_SYSCALL_ERROR_RETURN_VALUE (EBADF);
|
||||
|
||||
/* The pidfd cannot be resolved because it is in a separate pid
|
||||
namespace. */
|
||||
if (fdinfo.pid == 0)
|
||||
return INLINE_SYSCALL_ERROR_RETURN_VALUE (EREMOTE);
|
||||
|
||||
/* A negative value means the process is terminated. */
|
||||
if (fdinfo.pid < 0)
|
||||
return INLINE_SYSCALL_ERROR_RETURN_VALUE (ESRCH);
|
||||
|
||||
return fdinfo.pid;
|
||||
}
|
@ -2825,6 +2825,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2858,6 +2858,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2579,6 +2579,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2893,6 +2893,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
97
sysdeps/unix/sysv/linux/procutils.c
Normal file
97
sysdeps/unix/sysv/linux/procutils.c
Normal file
@ -0,0 +1,97 @@
|
||||
/* 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 int
|
||||
next_line (char **r, 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 = TEMP_FAILURE_RETRY (
|
||||
__read_nocancel (fd, *re, buffer_end - *re));
|
||||
if (n < 0)
|
||||
return -1;
|
||||
|
||||
*re += n;
|
||||
|
||||
nl = memchr (*cp, '\n', *re - *cp);
|
||||
if (nl == NULL)
|
||||
/* Line too long. */
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
nl = memchr (*cp, '\n', *re - *cp);
|
||||
|
||||
res = *cp;
|
||||
}
|
||||
|
||||
if (nl == NULL)
|
||||
nl = *re - 1;
|
||||
}
|
||||
|
||||
*nl = '\0';
|
||||
*cp = nl + 1;
|
||||
assert (*cp <= *re);
|
||||
|
||||
if (res == *re)
|
||||
return 0;
|
||||
|
||||
*r = res;
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool
|
||||
procutils_read_file (const char *filename, procutils_closure_t closure,
|
||||
void *arg)
|
||||
{
|
||||
enum { buffer_size = PROCUTILS_MAX_LINE_LEN };
|
||||
char buffer[buffer_size];
|
||||
char *buffer_end = buffer + buffer_size;
|
||||
char *cp = buffer_end;
|
||||
char *re = buffer_end;
|
||||
|
||||
int fd = TEMP_FAILURE_RETRY (
|
||||
__open64_nocancel (filename, O_RDONLY | O_CLOEXEC));
|
||||
if (fd == -1)
|
||||
return false;
|
||||
|
||||
char *l;
|
||||
int r;
|
||||
while ((r = next_line (&l, fd, buffer, &cp, &re, buffer_end)) > 0)
|
||||
if (closure (l, arg) != 0)
|
||||
break;
|
||||
|
||||
__close_nocancel_nostatus (fd);
|
||||
|
||||
return r == 1;
|
||||
}
|
43
sysdeps/unix/sysv/linux/procutils.h
Normal file
43
sysdeps/unix/sysv/linux/procutils.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* 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 int (*procutils_closure_t) (const char *line, void *arg);
|
||||
|
||||
#define PROCUTILS_MAX_LINE_LEN 256
|
||||
|
||||
/* 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 0 if the read should continue, otherwise the
|
||||
the function should stop and return early.
|
||||
|
||||
The '\n' is not included in the CLOSURE input argument and lines longer
|
||||
than PROCUTILS_MAX_LINE_LEN characteres are ignored.
|
||||
|
||||
It returns true in case the file is fully read or false if CLOSURE
|
||||
returns a value diferent than 0. */
|
||||
bool procutils_read_file (const char *filename, procutils_closure_t closure,
|
||||
void *arg) attribute_hidden;
|
||||
|
||||
#endif
|
@ -2436,6 +2436,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2636,6 +2636,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2823,6 +2823,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2616,6 +2616,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2666,6 +2666,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2663,6 +2663,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2818,6 +2818,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2631,6 +2631,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -46,4 +46,8 @@ extern int pidfd_getfd (int __pidfd, int __targetfd,
|
||||
extern int pidfd_send_signal (int __pidfd, int __sig, siginfo_t *__info,
|
||||
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>
|
||||
@ -27,6 +28,8 @@
|
||||
#include <support/xsocket.h>
|
||||
#include <sys/pidfd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define REMOTE_PATH "/dev/null"
|
||||
|
||||
@ -102,6 +105,44 @@ do_test (void)
|
||||
ppid = getpid ();
|
||||
puid = getuid ();
|
||||
|
||||
/* Sanity check for invalid inputs. */
|
||||
TEST_COMPARE (pidfd_getpid (-1), -1);
|
||||
TEST_COMPARE (errno, EBADF);
|
||||
|
||||
{
|
||||
pid_t pid = pidfd_getpid (STDOUT_FILENO);
|
||||
TEST_COMPARE (pid, -1);
|
||||
TEST_COMPARE (errno, EBADF);
|
||||
}
|
||||
|
||||
/* Check if pidfd_getpid returns ESRCH for exited subprocess. */
|
||||
{
|
||||
pid_t pidfork = xfork ();
|
||||
if (pidfork == 0)
|
||||
_exit (EXIT_SUCCESS);
|
||||
int pidfork_pidfd = pidfd_open (pidfork, 0);
|
||||
|
||||
/* The process might be still running or already in zombie state, in
|
||||
either case the PID is still allocated to the process. */
|
||||
pid_t pid = pidfd_getpid (pidfork_pidfd);
|
||||
TEST_COMPARE (pidfork, pid);
|
||||
if (pid > 0)
|
||||
support_process_state_wait (pid, support_process_state_zombie);
|
||||
|
||||
siginfo_t info;
|
||||
TEST_COMPARE (waitid (P_PIDFD, pidfork_pidfd, &info, WEXITED), 0);
|
||||
TEST_COMPARE (info.si_pid, pidfork);
|
||||
TEST_COMPARE (info.si_status, 0);
|
||||
TEST_COMPARE (info.si_code, CLD_EXITED);
|
||||
|
||||
/* Once the process is reaped the associated PID is not available. */
|
||||
pid = pidfd_getpid (pidfork_pidfd);
|
||||
TEST_COMPARE (pid, -1);
|
||||
TEST_COMPARE (errno, ESRCH);
|
||||
|
||||
xclose (pidfork_pidfd);
|
||||
}
|
||||
|
||||
TEST_COMPARE (socketpair (AF_UNIX, SOCK_STREAM, 0, sockets), 0);
|
||||
|
||||
pid_t pid = xfork ();
|
||||
@ -118,6 +159,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);
|
||||
|
123
sysdeps/unix/sysv/linux/tst-pidfd_getpid.c
Normal file
123
sysdeps/unix/sysv/linux/tst-pidfd_getpid.c
Normal file
@ -0,0 +1,123 @@
|
||||
/* Specific tests for Linux pidfd_getpid.
|
||||
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 <errno.h>
|
||||
#include <sched.h>
|
||||
#include <stdlib.h>
|
||||
#include <support/check.h>
|
||||
#include <support/xunistd.h>
|
||||
#include <support/test-driver.h>
|
||||
#include <sys/pidfd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
{
|
||||
/* The pidfd_getfd syscall was the last in the set of pidfd related
|
||||
syscalls added to the kernel. Use pidfd_getfd to decide if this
|
||||
kernel has pidfd support that we can test. */
|
||||
int r = pidfd_getfd (0, 0, 1);
|
||||
TEST_VERIFY_EXIT (r == -1);
|
||||
if (errno == ENOSYS)
|
||||
FAIL_UNSUPPORTED ("kernel does not support pidfd_getfd, skipping test");
|
||||
if (errno == EPERM)
|
||||
FAIL_UNSUPPORTED ("kernel does not allow pidfd_getfd, skipping test");
|
||||
}
|
||||
|
||||
/* Check if pidfd_getpid returns EREMOTE for process not in current
|
||||
namespace. */
|
||||
{
|
||||
pid_t child0 = xfork ();
|
||||
TEST_VERIFY_EXIT (child0 >= 0);
|
||||
if (child0 == 0)
|
||||
{
|
||||
/* Create another unrelated descriptor, so child2 will inherit the
|
||||
file descriptor. */
|
||||
pid_t child1 = xfork ();
|
||||
TEST_VERIFY_EXIT (child1 >= 0);
|
||||
if (child1 == 0)
|
||||
_exit (0);
|
||||
int child1_pidfd = pidfd_open (child1, 0);
|
||||
TEST_VERIFY_EXIT (child1_pidfd != -1);
|
||||
|
||||
if (unshare (CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWPID) < 0)
|
||||
{
|
||||
/* Older kernels may not support all the options, or security
|
||||
policy may block this call. */
|
||||
if (errno == EINVAL || errno == EPERM || errno == ENOSPC)
|
||||
exit (EXIT_UNSUPPORTED);
|
||||
FAIL_EXIT1 ("unshare user/fs/pid failed: %m");
|
||||
}
|
||||
|
||||
if (mount (NULL, "/", NULL, MS_REC | MS_PRIVATE, 0) != 0)
|
||||
{
|
||||
/* This happens if we're trying to create a nested container,
|
||||
like if the build is running under podman, and we lack
|
||||
priviledges. */
|
||||
if (errno == EPERM)
|
||||
_exit (EXIT_UNSUPPORTED);
|
||||
else
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pid_t child2 = xfork ();
|
||||
if (child2 > 0)
|
||||
{
|
||||
int status;
|
||||
xwaitpid (child2, &status, 0);
|
||||
TEST_VERIFY (WIFEXITED (status));
|
||||
xwaitpid (child1, &status, 0);
|
||||
TEST_VERIFY (WIFEXITED (status));
|
||||
|
||||
_exit (WEXITSTATUS (status));
|
||||
}
|
||||
|
||||
/* Now that we're pid 1 (effectively "root") we can mount /proc */
|
||||
if (mount ("proc", "/proc", "proc", 0, NULL) != 0)
|
||||
{
|
||||
if (errno == EPERM)
|
||||
_exit (EXIT_UNSUPPORTED);
|
||||
else
|
||||
_exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
TEST_COMPARE (pidfd_getpid (child1_pidfd), -1);
|
||||
TEST_COMPARE (errno, EREMOTE);
|
||||
|
||||
_exit (EXIT_SUCCESS);
|
||||
}
|
||||
int child0_pidfd = pidfd_open (child0, 0);
|
||||
TEST_VERIFY_EXIT (child0_pidfd != -1);
|
||||
|
||||
pid_t child0pid = pidfd_getpid (child0_pidfd);
|
||||
|
||||
siginfo_t info;
|
||||
TEST_COMPARE (waitid (P_PIDFD, child0_pidfd, &info, WEXITED), 0);
|
||||
if (info.si_status == EXIT_UNSUPPORTED)
|
||||
FAIL_UNSUPPORTED ("unable to unshare user/fs/pid");
|
||||
TEST_COMPARE (info.si_status, 0);
|
||||
TEST_COMPARE (info.si_code, CLD_EXITED);
|
||||
TEST_COMPARE (info.si_pid, child0pid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
@ -2582,6 +2582,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
@ -2688,6 +2688,7 @@ GLIBC_2.38 strlcat F
|
||||
GLIBC_2.38 strlcpy F
|
||||
GLIBC_2.38 wcslcat F
|
||||
GLIBC_2.38 wcslcpy F
|
||||
GLIBC_2.39 pidfd_getpid F
|
||||
GLIBC_2.39 pidfd_spawn F
|
||||
GLIBC_2.39 pidfd_spawnp F
|
||||
GLIBC_2.39 posix_spawnattr_getcgroup_np F
|
||||
|
Loading…
Reference in New Issue
Block a user