Browse Source

common: add pidfd related methods

Add functions to open pidfds, i.e. file descriptors representing
processes, for process ids and vice versa. Both functions work
an array of fds/pids, stop on error and return the number of
successfully handled items.
Christian Kellner 5 năm trước cách đây
mục cha
commit
5398dd1d19
4 tập tin đã thay đổi với 266 bổ sung0 xóa
  1. 207 0
      common/common-pidfds.c
  2. 53 0
      common/common-pidfds.h
  3. 2 0
      common/meson.build
  4. 4 0
      meson.build

+ 207 - 0
common/common-pidfds.c

@@ -0,0 +1,207 @@
+/*
+
+Copyright (c) 2017-2019, Feral Interactive
+Copyright (c) 2019, Red Hat
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+ * Neither the name of Feral Interactive nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+#define _GNU_SOURCE
+#include <build-config.h>
+
+#include "common-helpers.h"
+#include "common-pidfds.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#if !HAVE_FN_PIDFD_OPEN
+#include <sys/syscall.h>
+
+#ifndef __NR_pidfd_open
+#define __NR_pidfd_open 434
+#endif
+
+static int pidfd_open(pid_t pid, unsigned int flags)
+{
+	return (int)syscall(__NR_pidfd_open, pid, flags);
+}
+#endif
+
+/* pidfd functions */
+int open_pidfds(pid_t *pids, int *fds, int count)
+{
+	int i = 0;
+
+	for (i = 0; i < count; i++) {
+		int pid = pids[i];
+		int fd = pidfd_open(pid, 0);
+
+		if (fd < 0)
+			break;
+
+		fds[i] = fd;
+	}
+
+	return i;
+}
+
+static int parse_pid(const char *str, pid_t *pid)
+{
+	unsigned long long int v;
+	char *end;
+	pid_t p;
+
+	errno = 0;
+	v = strtoull(str, &end, 0);
+	if (end == str)
+		return -ENOENT;
+	else if (errno != 0)
+		return -errno;
+
+	p = (pid_t)v;
+
+	if (p < 1 || (unsigned long long int)p != v)
+		return -ERANGE;
+
+	if (pid)
+		*pid = p;
+
+	return 0;
+}
+
+static int parse_status_field_pid(const char *val, pid_t *pid)
+{
+	const char *t;
+
+	t = strrchr(val, '\t');
+	if (t == NULL)
+		return -ENOENT;
+
+	return parse_pid(t, pid);
+}
+
+static int pidfd_to_pid(int fdinfo, int pidfd, pid_t *pid)
+{
+	autofree char *key = NULL;
+	autofree char *val = NULL;
+	char name[256] = {
+		0,
+	};
+	bool found = false;
+	FILE *f = NULL;
+	size_t keylen = 0;
+	size_t vallen = 0;
+	ssize_t n;
+	int fd;
+	int r = 0;
+
+	*pid = 0;
+
+	buffered_snprintf(name, "%d", pidfd);
+
+	fd = openat(fdinfo, name, O_RDONLY | O_CLOEXEC | O_NOCTTY);
+
+	if (fd != -1)
+		f = fdopen(fd, "r");
+
+	if (f == NULL)
+		return -errno;
+
+	do {
+		n = getdelim(&key, &keylen, ':', f);
+		if (n == -1) {
+			r = errno;
+			break;
+		}
+
+		n = getdelim(&val, &vallen, '\n', f);
+		if (n == -1) {
+			r = errno;
+			break;
+		}
+
+		// TODO: strstrip (key);
+
+		if (!strncmp(key, "Pid", 3)) {
+			r = parse_status_field_pid(val, pid);
+			found = r > -1;
+		}
+
+	} while (r == 0 && !found);
+
+	fclose(f);
+
+	if (r < 0)
+		return r;
+	else if (!found)
+		return -ENOENT;
+
+	return 0;
+}
+
+int pidfds_to_pids(int *fds, pid_t *pids, int count)
+{
+	int fdinfo = -1;
+	int r = 0;
+	int i;
+
+	fdinfo = open_fdinfo_dir();
+	if (fdinfo == -1)
+		return -1;
+
+	for (i = 0; i < count && r == 0; i++)
+		r = pidfd_to_pid(fdinfo, fds[i], &pids[i]);
+
+	(void)close(fdinfo);
+
+	if (r != 0)
+		errno = -r;
+
+	return i;
+}
+
+/* misc directory helpers */
+int open_fdinfo_dir(void)
+{
+	int fd;
+
+	fd = open("/proc/self/fdinfo", O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
+
+	if (fd == -1)
+		return errno;
+
+	return fd;
+}

+ 53 - 0
common/common-pidfds.h

@@ -0,0 +1,53 @@
+/*
+
+Copyright (c) 2017-2019, Feral Interactive
+Copyright (c) 2019, Red Hat
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+ * Neither the name of Feral Interactive nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include <sys/types.h>
+
+/* Open pidfds for up to count process ids specified in pids. The
+ * pointer fds needs to point to an array with at least count
+ * entries. Will stop when it encounters an error (and sets errno).
+ * Returns the number of successfully opened pidfds (or -1 in case
+ * of other errors. */
+int open_pidfds(pid_t *pids, int *fds, int count);
+
+/* Translate up to count process ids to the corresponding process ids.
+ * The pointer pids needs to point to an array with at least count
+ * entries. Will stop when it encounters an error (and sets errno).
+ * Returns the number of successfully translated pidfds (or -1 in
+ * case of other errors. */
+int pidfds_to_pids(int *fds, pid_t *pids, int count);
+
+/* Helper to open the fdinfo directory for the current process, i.e.
+ * does open("/proc/self/fdinfo", ...). Returns the file descriptor
+ * for the directory, ownership is transferred and caller needs to
+ * call close on it. */
+int open_fdinfo_dir(void);

+ 2 - 0
common/meson.build

@@ -5,12 +5,14 @@ common_sources = [
     'common-external.c',
     'common-helpers.c',
     'common-gpu.c',
+    'common-pidfds.c',
 ]
 
 daemon_common = static_library(
     'daemon-common',
     sources: common_sources,
     install: false,
+    include_directories: [config_h_dir]
 )
 
 link_daemon_common = declare_dependency(

+ 4 - 0
meson.build

@@ -128,9 +128,13 @@ with_examples = get_option('with-examples')
 with_util = get_option('with-util')
 
 # Provide a config.h
+pidfd_open = cc.has_function('pidfd_open', args: '-D_GNU_SOURCE')
+
 cdata = configuration_data()
 cdata.set_quoted('LIBEXECDIR', path_libexecdir)
 cdata.set_quoted('GAMEMODE_VERSION', meson.project_version())
+cdata.set10('HAVE_FN_PIDFD_OPEN', pidfd_open)
+
 config_h = configure_file(
     configuration: cdata,
     output: 'build-config.h',