#include <sys/types.h>
+typedef enum NamespaceType NamespaceType;
+
#include "pidref.h"
-typedef enum NamespaceType {
+enum NamespaceType {
NAMESPACE_CGROUP,
NAMESPACE_IPC,
NAMESPACE_NET,
NAMESPACE_TIME,
_NAMESPACE_TYPE_MAX,
_NAMESPACE_TYPE_INVALID = -EINVAL,
-} NamespaceType;
+};
extern const struct namespace_info {
const char *proc_name;
}
}
+bool pidref_is_automatic(const PidRef *pidref) {
+ return pidref && pid_is_automatic(pidref->pid);
+}
+
static void pidref_hash_func(const PidRef *pidref, struct siphash *state) {
siphash24_compress_typesafe(pidref->pid, state);
}
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+typedef struct PidRef PidRef;
+
#include "macro.h"
+#include "process-util.h"
/* An embeddable structure carrying a reference to a process. Supposed to be used when tracking processes continuously. */
-typedef struct PidRef {
+struct PidRef {
pid_t pid; /* always valid */
int fd; /* only valid if pidfd are available in the kernel, and we manage to get an fd */
uint64_t fd_id; /* the inode number of pidfd. only useful in kernel 6.9+ where pidfds live in
their own pidfs and each process comes with a unique inode number */
-} PidRef;
+};
#define PIDREF_NULL (const PidRef) { .fd = -EBADF }
+/* A special pidref value that we are using when a PID shall be automatically acquired from some surrounding
+ * context, for example connection peer. Much like PIDREF_NULL it will be considerd unset by
+ * pidref_is_set().*/
+#define PIDREF_AUTOMATIC (const PidRef) { .pid = PID_AUTOMATIC, .fd = -EBADF }
+
/* Turns a pid_t into a PidRef structure on-the-fly *without* acquiring a pidfd for it. (As opposed to
* pidref_set_pid() which does so *with* acquiring one, see below) */
#define PIDREF_MAKE_FROM_PID(x) (PidRef) { .pid = (x), .fd = -EBADF }
return pidref && pidref->pid > 0;
}
+bool pidref_is_automatic(const PidRef *pidref);
+
int pidref_acquire_pidfd_id(PidRef *pidref);
bool pidref_equal(PidRef *a, PidRef *b);
#include "format-util.h"
#include "macro.h"
#include "namespace-util.h"
+#include "pidref.h"
#include "time-util.h"
#define procfs_file_alloca(pid, field) \
return i >= 0 && i <= sched_get_priority_max(SCHED_RR);
}
-#define PID_AUTOMATIC ((pid_t) INT_MIN) /* special value indicating "acquire pid from connection peer */
+#define PID_AUTOMATIC ((pid_t) INT_MIN) /* special value indicating "acquire pid from connection peer" */
#define PID_INVALID ((pid_t) 0) /* default value for "invalid pid" */
static inline bool pid_is_valid(pid_t p) {
* above. If SD_JSON_STRICT is set this will acquire a pidfd for the process, and validate that the
* auxiliary fields match it. Otherwise, this will just store the pid and the pidfd inode number (the
* latter not if the provided boot id differs from the local one), and not attempt to get a pidfd for
- * it, or authenticate it. */
+ * it, or authenticate it.
+ *
+ * If SD_JSON_RELAX is specified, a specified but zero/empty PID will be mapped to PIDREF_AUTOMATIC,
+ * which is supposed to indicate that the PID shall be automatically derived, typically from the
+ * connection peer.
+ *
+ * Note that SD_JSON_RELAX and SD_JSON_STRICT can be combined. */
if (sd_json_variant_is_null(variant)) {
pidref_done(p);
} else
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is neither a numeric PID nor a PID object.", strna(name));
+ /* If SD_JSON_RELAX is set then we'll take a specified but zero field as request for "automic" PID derivation */
+ if ((flags & SD_JSON_RELAX) && data.pid == 0 && data.fd_id == 0 && sd_id128_is_null(data.boot_id)) {
+ pidref_done(p);
+ *p = PIDREF_AUTOMATIC;
+ return 0;
+ }
+
/* Before casting the 64bit data.pid field to pid_t, let's ensure it fits the pid_t range. */
if (data.pid > PID_T_MAX || !pid_is_valid(data.pid))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' does not contain a valid PID.", strna(name));
assert_se(pidref_verify(&pidref) == (pidref.fd >= 0));
}
+TEST(pidref_is_automatic) {
+ assert_se(!pidref_is_automatic(NULL));
+ assert_se(!pidref_is_automatic(&PIDREF_NULL));
+ assert_se(!pidref_is_automatic(&PIDREF_MAKE_FROM_PID(1)));
+ assert_se(!pidref_is_automatic(&PIDREF_MAKE_FROM_PID(getpid_cached())));
+ assert_se(pidref_is_automatic(&PIDREF_AUTOMATIC));
+
+ assert_se(!pid_is_automatic(0));
+ assert_se(!pid_is_automatic(1));
+ assert_se(!pid_is_automatic(getpid_cached()));
+ assert_se(pid_is_automatic(PID_AUTOMATIC));
+
+ assert_se(!pidref_is_set(&PIDREF_AUTOMATIC));
+ assert_se(!pid_is_valid(PID_AUTOMATIC));
+}
+
DEFINE_TEST_MAIN(LOG_DEBUG);