1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
|
/* WirePlumber
*
* Copyright © 2024 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <stdio.h>
#include "log.h"
#include "proc-utils.h"
#define MAX_ARGS 1024
WP_DEFINE_LOCAL_LOG_TOPIC ("wp-proc-utils")
/*! \defgroup wpprocutils Process Utilities */
/*!
* \struct WpProcInfo
*
* WpProcInfo holds information of a process.
*/
struct _WpProcInfo {
grefcount ref;
pid_t pid;
pid_t parent;
gchar *cgroup;
gchar *args[MAX_ARGS];
guint n_args;
};
G_DEFINE_BOXED_TYPE (WpProcInfo, wp_proc_info, wp_proc_info_ref,
wp_proc_info_unref)
/*!
* \brief Increases the reference count of a process information object
* \ingroup wpprocutils
* \param self a process information object
* \returns (transfer full): \a self with an additional reference count on it
*/
WpProcInfo *
wp_proc_info_ref (WpProcInfo * self)
{
g_ref_count_inc (&self->ref);
return self;
}
static void
wp_proc_info_free (WpProcInfo * self)
{
g_clear_pointer (&self->cgroup, g_free);
for (guint i = 0; i < MAX_ARGS; i++)
g_clear_pointer (&self->args[i], free);
g_slice_free (WpProcInfo, self);
}
/*!
* \brief Decreases the reference count on \a self and frees it when the ref
* count reaches zero.
* \ingroup wpprocutils
* \param self (transfer full): a process information object
*/
void
wp_proc_info_unref (WpProcInfo * self)
{
if (g_ref_count_dec (&self->ref))
wp_proc_info_free (self);
}
static WpProcInfo *
wp_proc_info_new (pid_t pid)
{
WpProcInfo *self = g_slice_new0 (WpProcInfo);
g_ref_count_init (&self->ref);
self->pid = pid;
self->parent = 0;
self->cgroup = NULL;
for (guint i = 0; i < MAX_ARGS; i++)
self->args[i] = NULL;
return self;
}
/*!
* \brief Gets the PID of a process information object
* \ingroup wpprocutils
* \param self the process information object
* \returns the PID of the process information object
*/
pid_t
wp_proc_info_get_pid (WpProcInfo * self)
{
return self->pid;
}
/*!
* \brief Gets the parent PID of a process information object
* \ingroup wpprocutils
* \param self the process information object
* \returns the parent PID of the process information object
*/
pid_t
wp_proc_info_get_parent_pid (WpProcInfo * self)
{
return self->parent;
}
/*!
* \brief Gets the number of args of a process information object
* \ingroup wpprocutils
* \param self the process information object
* \returns the number of args of the process information object
*/
guint
wp_proc_info_get_n_args (WpProcInfo * self)
{
return self->n_args;
}
/*!
* \brief Gets the indexed arg of a process information object
* \ingroup wpprocutils
* \param self the process information object
* \param index the index of the arg
* \returns the indexed arg of the process information object
*/
const gchar *
wp_proc_info_get_arg (WpProcInfo * self, guint index)
{
if (index >= self->n_args)
return NULL;
return self->args[index];
}
/*!
* \brief Gets the systemd cgroup of a process information object
* \ingroup wpprocutils
* \param self the process information object
* \returns the systemd cgroup of the process information object
*/
const gchar *
wp_proc_info_get_cgroup (WpProcInfo * self)
{
return self->cgroup;
}
/*!
* \brief Gets the process information of a given PID
* \ingroup wpprocutils
* \param pid the PID to get the process information from
* \returns: (transfer full): the process information of the given PID
*/
WpProcInfo *
wp_proc_utils_get_proc_info (pid_t pid)
{
WpProcInfo *ret = wp_proc_info_new (pid);
g_autofree gchar *status = NULL;
g_autoptr (GError) error = NULL;
gsize length = 0;
/* Get parent PID */
{
g_autofree gchar *path = g_strdup_printf ("/proc/%d/status", pid);
if (g_file_get_contents (path, &status, &length, &error)) {
const gchar *loc = strstr (status, "\nPPid:");
if (loc) {
const gint res = sscanf (loc, "\nPPid:%d\n", &ret->parent);
if (!res || res == EOF)
wp_warning ("failed to parse status PPID for PID %d", pid);
} else {
wp_warning ("failed to find status parent PID for PID %d", pid);
}
} else {
wp_warning ("failed to get status for PID %d: %s", pid, error->message);
}
}
/* Get cgroup */
{
g_autofree gchar *path = g_strdup_printf ("/proc/%d/cgroup", pid);
if (g_file_get_contents (path, &ret->cgroup, &length, &error)) {
if (length > 0)
ret->cgroup [length - 1] = '\0'; /* Remove EOF character */
} else {
wp_warning ("failed to get cgroup for PID %d: %s", pid, error->message);
}
}
/* Get args */
{
g_autofree gchar *path = g_strdup_printf ("/proc/%d/cmdline", pid);
FILE *file = fopen (path, "rb");
if (file) {
g_autofree gchar *lineptr = NULL;
size_t size = 0;
while (getdelim (&lineptr, &size, 0, file) > 1 && ret->n_args < MAX_ARGS)
ret->args[ret->n_args++] = g_strdup (lineptr);
fclose (file);
} else {
wp_warning ("failed to get cmdline for PID %d: %m", pid);
}
}
return ret;
}
|