File: proc-utils.c

package info (click to toggle)
wireplumber 0.5.12-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,244 kB
  • sloc: ansic: 41,043; python: 391; sh: 62; makefile: 57; xml: 23
file content (206 lines) | stat: -rw-r--r-- 5,100 bytes parent folder | download | duplicates (2)
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;
}