mips: FIx clone3 implementation (BZ 31325)
[glibc.git] / sysdeps / unix / sysv / linux / pidfd_getpid.c
blob8567b413dd2c210b3108711e83de32db08d5db0b
1 /* pidfd_getpid - Get the associated pid from the pid file descriptor.
2 Copyright (C) 2023-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library 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 GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <_itoa.h>
20 #include <errno.h>
21 #include <intprops.h>
22 #include <procutils.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sysdep.h>
26 #include <unistd.h>
28 #define FDINFO_TO_FILENAME_PREFIX "/proc/self/fdinfo/"
30 #define FDINFO_FILENAME_LEN \
31 (sizeof (FDINFO_TO_FILENAME_PREFIX) + INT_STRLEN_BOUND (int))
33 struct parse_fdinfo_t
35 bool found;
36 pid_t pid;
39 /* Parse the PID field in the fdinfo entry, if existent. Avoid strtol or
40 similar to not be locale dependent. */
41 static int
42 parse_fdinfo (const char *l, void *arg)
44 enum { fieldlen = sizeof ("Pid:") - 1 };
45 if (strncmp (l, "Pid:", fieldlen) != 0)
46 return 0;
48 l += fieldlen;
50 /* Skip leading spaces. */
51 while (*l == ' ' || (unsigned int) (*l) -'\t' < 5)
52 l++;
54 bool neg = false;
55 switch (*l)
57 case '-':
58 neg = true;
59 l++;
60 break;
61 case '+':
62 return -1;
65 if (*l == '\0')
66 return 0;
68 int n = 0;
69 while (*l != '\0')
71 /* Check if '*l' is a digit. */
72 if ('0' > *l || *l > '9')
73 return -1;
75 /* Ignore invalid large values. */
76 if (INT_MULTIPLY_WRAPV (10, n, &n)
77 || INT_ADD_WRAPV (n, *l++ - '0', &n))
78 return -1;
81 /* -1 indicates that the process is terminated. */
82 if (neg && n != 1)
83 return -1;
85 struct parse_fdinfo_t *fdinfo = arg;
86 fdinfo->pid = neg ? -n : n;
87 fdinfo->found = true;
89 return 1;
92 pid_t
93 pidfd_getpid (int fd)
95 if (__glibc_unlikely (fd < 0))
97 __set_errno (EBADF);
98 return -1;
101 char fdinfoname[FDINFO_FILENAME_LEN];
103 char *p = mempcpy (fdinfoname, FDINFO_TO_FILENAME_PREFIX,
104 strlen (FDINFO_TO_FILENAME_PREFIX));
105 *_fitoa_word (fd, p, 10, 0) = '\0';
107 struct parse_fdinfo_t fdinfo = { .found = false, .pid = -1 };
108 if (!procutils_read_file (fdinfoname, parse_fdinfo, &fdinfo))
109 /* The fdinfo contains an invalid 'Pid:' value. */
110 return INLINE_SYSCALL_ERROR_RETURN_VALUE (EBADF);
112 /* The FD does not have a 'Pid:' entry associated. */
113 if (!fdinfo.found)
114 return INLINE_SYSCALL_ERROR_RETURN_VALUE (EBADF);
116 /* The pidfd cannot be resolved because it is in a separate pid
117 namespace. */
118 if (fdinfo.pid == 0)
119 return INLINE_SYSCALL_ERROR_RETURN_VALUE (EREMOTE);
121 /* A negative value means the process is terminated. */
122 if (fdinfo.pid < 0)
123 return INLINE_SYSCALL_ERROR_RETURN_VALUE (ESRCH);
125 return fdinfo.pid;