2 * Copyright (C) 2011 Davidlohr Bueso <dave@gnu.org>
4 * procutils.c: General purpose procfs parsing utilities
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Library Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Library Public License for more details.
21 #include <sys/types.h>
25 #include "procutils.h"
30 * @pid: process ID for which we want to obtain the threads group
32 * Returns: newly allocated tasks structure
34 struct proc_tasks
*proc_open_tasks(pid_t pid
)
36 struct proc_tasks
*tasks
;
39 sprintf(path
, "/proc/%d/task/", pid
);
41 tasks
= malloc(sizeof(struct proc_tasks
));
43 tasks
->dir
= opendir(path
);
53 * @tasks: allocated tasks structure
57 void proc_close_tasks(struct proc_tasks
*tasks
)
59 if (tasks
&& tasks
->dir
)
65 * @tasks: allocated task structure
66 * @tid: [output] one of the thread IDs belonging to the thread group
67 * If when an error occurs, it is set to 0.
69 * Returns: 0 on success, 1 on end, -1 on failure or no more threads
71 int proc_next_tid(struct proc_tasks
*tasks
, pid_t
*tid
)
83 d
= readdir(tasks
->dir
);
85 return errno
? -1 : 1; /* error or end-of-dir */
87 if (!isdigit((unsigned char) *d
->d_name
))
90 *tid
= (pid_t
) strtol(d
->d_name
, &end
, 10);
91 if (errno
|| d
->d_name
== end
|| (end
&& *end
))
99 struct proc_processes
*proc_open_processes(void)
101 struct proc_processes
*ps
;
103 ps
= calloc(1, sizeof(struct proc_processes
));
105 ps
->dir
= opendir("/proc");
114 void proc_close_processes(struct proc_processes
*ps
)
121 void proc_processes_filter_by_name(struct proc_processes
*ps
, const char *name
)
123 ps
->fltr_name
= name
;
124 ps
->has_fltr_name
= name
? 1 : 0;
127 void proc_processes_filter_by_uid(struct proc_processes
*ps
, uid_t uid
)
130 ps
->has_fltr_uid
= 1;
133 int proc_next_pid(struct proc_processes
*ps
, pid_t
*pid
)
144 char buf
[BUFSIZ
], *p
;
146 d
= readdir(ps
->dir
);
148 return errno
? -1 : 1; /* error or end-of-dir */
151 if (!isdigit((unsigned char) *d
->d_name
))
154 snprintf(buf
, sizeof(buf
), "%s/stat", d
->d_name
);
156 /* filter out by UID */
157 if (ps
->has_fltr_uid
) {
160 if (fstat_at(dirfd(ps
->dir
), "/proc", buf
, &st
, 0))
162 if (ps
->fltr_uid
!= st
.st_uid
)
166 /* filter out by NAME */
167 if (ps
->has_fltr_name
) {
169 FILE *f
= fopen_at(dirfd(ps
->dir
), "/proc", buf
,
170 O_CLOEXEC
|O_RDONLY
, "r");
174 p
= fgets(buf
, sizeof(buf
), f
);
177 if (sscanf(buf
, "%*d (%255[^)])", procname
) != 1)
180 /* ok, we got the process name. */
181 if (strcmp(procname
, ps
->fltr_name
) != 0)
186 *pid
= (pid_t
) strtol(d
->d_name
, &p
, 10);
187 if (errno
|| d
->d_name
== p
|| (p
&& *p
))
188 return errno
? -errno
: -1;
198 static int test_tasks(int argc
, char *argv
[])
201 struct proc_tasks
*ts
;
206 pid
= strtol(argv
[1], (char **) NULL
, 10);
207 printf("PID=%d, TIDs:", pid
);
209 ts
= proc_open_tasks(pid
);
211 err(EXIT_FAILURE
, "open list of tasks failed");
213 while (proc_next_tid(ts
, &tid
) == 0)
217 proc_close_tasks(ts
);
221 static int test_processes(int argc
, char *argv
[])
224 struct proc_processes
*ps
;
226 ps
= proc_open_processes();
228 err(EXIT_FAILURE
, "open list of processes failed");
230 if (argc
>= 3 && strcmp(argv
[1], "--name") == 0)
231 proc_processes_filter_by_name(ps
, argv
[2]);
233 if (argc
>= 3 && strcmp(argv
[1], "--uid") == 0)
234 proc_processes_filter_by_uid(ps
, (uid_t
) atol(argv
[2]));
236 while (proc_next_pid(ps
, &pid
) == 0)
240 proc_close_processes(ps
);
244 int main(int argc
, char *argv
[])
247 fprintf(stderr
, "usage: %1$s --tasks <pid>\n"
248 " %1$s --processes [---name <name>] [--uid <uid>]\n",
249 program_invocation_short_name
);
253 if (strcmp(argv
[1], "--tasks") == 0)
254 return test_tasks(argc
- 1, argv
+ 1);
255 if (strcmp(argv
[1], "--processes") == 0)
256 return test_processes(argc
- 1, argv
+ 1);
260 #endif /* TEST_PROGRAM */