lib/procfs: add functions to read /proc/#/ stuff
This is extension to lib/path.c (the same as lib/sysfs.c for block devices) to read info about processes. * replaces code from lib/procutils.c * remove proc_{open,close}_processes(), opendir and readdir is good enough * add procfs_dirent_*() functions to work with readdir() from /proc * add new path_cxt based API (will be extended in next commits) for complex tasks Signed-off-by: Karel Zak <kzak@redhat.com>pull/1487/head
parent
2f26f8aae1
commit
32c21c7681
|
@ -49,6 +49,7 @@ dist_noinst_HEADERS += \
|
|||
include/pidfd-utils.h \
|
||||
include/plymouth-ctrl.h \
|
||||
include/procutils.h \
|
||||
include/procfs.h \
|
||||
include/pt-bsd.h \
|
||||
include/pt-mbr.h \
|
||||
include/pt-mbr-partnames.h \
|
||||
|
|
|
@ -88,6 +88,7 @@
|
|||
|
||||
/* mount paths */
|
||||
#define _PATH_FILESYSTEMS "/etc/filesystems"
|
||||
#define _PATH_PROC "/proc"
|
||||
#define _PATH_PROC_SWAPS "/proc/swaps"
|
||||
#define _PATH_PROC_FILESYSTEMS "/proc/filesystems"
|
||||
#define _PATH_PROC_MOUNTS "/proc/mounts"
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Karel Zak <kzak@redhat.com>
|
||||
*/
|
||||
#ifndef UTIL_LINUX_PROCFS_H
|
||||
#define UTIL_LINUX_PROCFS_H
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "path.h"
|
||||
|
||||
struct procfs_process {
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
extern void ul_procfs_init_debug(void);
|
||||
extern struct path_cxt *ul_new_procfs_path(pid_t pid, const char *prefix);
|
||||
extern int procfs_process_init_path(struct path_cxt *pc, pid_t pid);
|
||||
|
||||
extern int procfs_process_get_uid(struct path_cxt *pc, uid_t *uid);
|
||||
extern ssize_t procfs_process_get_cmdline(struct path_cxt *pc, char *buf, size_t bufsz);
|
||||
extern ssize_t procfs_process_get_cmdname(struct path_cxt *pc, char *buf, size_t bufsz);
|
||||
|
||||
|
||||
static inline ssize_t procfs_process_get_exe(struct path_cxt *pc, char *buf, size_t bufsz)
|
||||
{
|
||||
return ul_path_readlink(pc, buf, bufsz, "exe");
|
||||
}
|
||||
|
||||
static inline ssize_t procfs_process_get_root(struct path_cxt *pc, char *buf, size_t bufsz)
|
||||
{
|
||||
return ul_path_readlink(pc, buf, bufsz, "root");
|
||||
}
|
||||
|
||||
static inline ssize_t procfs_process_get_cwd(struct path_cxt *pc, char *buf, size_t bufsz)
|
||||
{
|
||||
return ul_path_readlink(pc, buf, bufsz, "cwd");
|
||||
}
|
||||
|
||||
extern int procfs_process_next_tid(struct path_cxt *pc, DIR **sub, pid_t *tid);
|
||||
extern int procfs_process_next_fd(struct path_cxt *pc, DIR **sub, int *fd);
|
||||
|
||||
extern int procfs_dirent_is_process(struct dirent *d);
|
||||
extern int procfs_dirent_get_pid(struct dirent *d, pid_t *pid);
|
||||
extern int procfs_dirent_get_uid(DIR *procfs, struct dirent *d, uid_t *uid);
|
||||
extern int procfs_dirent_match_uid(DIR *procfs, struct dirent *d, uid_t uid);
|
||||
extern int procfs_dirent_get_name(DIR *procfs, struct dirent *d, char *buf, size_t bufsz);
|
||||
extern int procfs_dirent_match_name(DIR *procfs, struct dirent *d, const char *name);
|
||||
|
||||
extern int fd_is_procfs(int fd);
|
||||
extern char *pid_get_cmdname(pid_t pid);
|
||||
extern char *pid_get_cmdline(pid_t pid);
|
||||
|
||||
#endif /* UTIL_LINUX_PROCFS_H */
|
|
@ -58,6 +58,7 @@ if HAVE_OPENAT
|
|||
if HAVE_DIRFD
|
||||
libcommon_la_SOURCES += lib/path.c
|
||||
libcommon_la_SOURCES += lib/sysfs.c
|
||||
libcommon_la_SOURCES += lib/procfs.c
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -102,6 +103,7 @@ check_PROGRAMS += test_cpuset
|
|||
endif
|
||||
check_PROGRAMS += \
|
||||
test_sysfs \
|
||||
test_procfs \
|
||||
test_pager \
|
||||
test_caputils \
|
||||
test_loopdev \
|
||||
|
@ -110,7 +112,6 @@ endif
|
|||
|
||||
if HAVE_OPENAT
|
||||
if HAVE_DIRFD
|
||||
check_PROGRAMS += test_procutils
|
||||
check_PROGRAMS += test_path
|
||||
endif
|
||||
endif
|
||||
|
@ -149,9 +150,6 @@ test_randutils_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_RANDUTILS
|
|||
|
||||
if HAVE_OPENAT
|
||||
if HAVE_DIRFD
|
||||
test_procutils_SOURCES = lib/procutils.c
|
||||
test_procutils_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_PROCUTILS
|
||||
|
||||
test_path_SOURCES = lib/path.c lib/fileutils.c
|
||||
if HAVE_CPU_SET_T
|
||||
test_path_SOURCES += lib/cpuset.c
|
||||
|
@ -181,6 +179,10 @@ endif
|
|||
test_sysfs_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_SYSFS
|
||||
test_sysfs_LDADD = $(LDADD)
|
||||
|
||||
test_procfs_SOURCES = lib/procfs.c lib/path.c lib/fileutils.c lib/strutils.c
|
||||
test_procfs_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_PROCFS
|
||||
test_procfs_LDADD = $(LDADD)
|
||||
|
||||
test_pager_SOURCES = lib/pager.c
|
||||
test_pager_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_PAGER
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ lib_common_sources = '''
|
|||
mbsedit.c
|
||||
md5.c
|
||||
pager.c
|
||||
procutils.c
|
||||
procfs.c
|
||||
pwdutils.c
|
||||
randutils.c
|
||||
sha1.c
|
||||
|
@ -74,7 +74,7 @@ endif
|
|||
if conf.get('HAVE_OPENAT') in [1] and conf.get('HAVE_DIRFD') in [1]
|
||||
lib_common_sources += '''
|
||||
path.c
|
||||
procutils.c
|
||||
procfs.c
|
||||
sysfs.c
|
||||
'''.split()
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,560 @@
|
|||
/*
|
||||
* No copyright is claimed. This code is in the public domain; do with
|
||||
* it what you wish.
|
||||
*
|
||||
* Written by Karel Zak <kzak@redhat.com>
|
||||
*/
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "c.h"
|
||||
#include "pathnames.h"
|
||||
#include "procfs.h"
|
||||
#include "fileutils.h"
|
||||
#include "all-io.h"
|
||||
#include "debug.h"
|
||||
#include "strutils.h"
|
||||
#include "statfs_magic.h"
|
||||
|
||||
static void procfs_process_deinit_path(struct path_cxt *pc);
|
||||
|
||||
/*
|
||||
* Debug stuff (based on include/debug.h)
|
||||
*/
|
||||
static UL_DEBUG_DEFINE_MASK(ulprocfs);
|
||||
UL_DEBUG_DEFINE_MASKNAMES(ulprocfs) = UL_DEBUG_EMPTY_MASKNAMES;
|
||||
|
||||
#define ULPROCFS_DEBUG_INIT (1 << 1)
|
||||
#define ULPROCFS_DEBUG_CXT (1 << 2)
|
||||
|
||||
#define DBG(m, x) __UL_DBG(ulprocfs, ULPROCFS_DEBUG_, m, x)
|
||||
#define ON_DBG(m, x) __UL_DBG_CALL(ulprocfs, ULPROCFS_DEBUG_, m, x)
|
||||
|
||||
#define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(ulprocfs)
|
||||
#include "debugobj.h"
|
||||
|
||||
void ul_procfs_init_debug(void)
|
||||
{
|
||||
if (ulprocfs_debug_mask)
|
||||
return;
|
||||
__UL_INIT_DEBUG_FROM_ENV(ulprocfs, ULPROCFS_DEBUG_, 0, ULPROCFS_DEBUG);
|
||||
}
|
||||
|
||||
struct path_cxt *ul_new_procfs_path(pid_t pid, const char *prefix)
|
||||
{
|
||||
struct path_cxt *pc = ul_new_path(NULL);
|
||||
|
||||
if (!pc)
|
||||
return NULL;
|
||||
if (prefix)
|
||||
ul_path_set_prefix(pc, prefix);
|
||||
|
||||
if (procfs_process_init_path(pc, pid) != 0) {
|
||||
ul_unref_path(pc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBG(CXT, ul_debugobj(pc, "alloc"));
|
||||
return pc;
|
||||
}
|
||||
|
||||
/*
|
||||
* procfs_blkdev_* is procfs extension to ul_path_* API to read info about process.
|
||||
*
|
||||
* The function is possible to call in loop and without sysfs_procfs_deinit_path().
|
||||
* The procfs_process_deinit_path() is automatically called by ul_unref_path().
|
||||
*
|
||||
*/
|
||||
int procfs_process_init_path(struct path_cxt *pc, pid_t pid)
|
||||
{
|
||||
struct procfs_process *prc;
|
||||
int rc;
|
||||
char buf[sizeof(_PATH_PROC) + sizeof(stringify_value(UINT32_MAX)) + 2];
|
||||
|
||||
/* define path to pid stuff */
|
||||
snprintf(buf, sizeof(buf), _PATH_PROC "/%zu", (size_t) pid);
|
||||
rc = ul_path_set_dir(pc, buf);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* make sure path exists */
|
||||
rc = ul_path_get_dirfd(pc);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* initialize procfs specific stuff */
|
||||
prc = ul_path_get_dialect(pc);
|
||||
if (!prc) {
|
||||
DBG(CXT, ul_debugobj(pc, "alloc new procfs handler"));
|
||||
prc = calloc(1, sizeof(struct procfs_process));
|
||||
if (!prc)
|
||||
return -ENOMEM;
|
||||
|
||||
ul_path_set_dialect(pc, prc, procfs_process_deinit_path);
|
||||
}
|
||||
|
||||
DBG(CXT, ul_debugobj(pc, "init procfs stuff"));
|
||||
|
||||
prc->pid = pid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void procfs_process_deinit_path(struct path_cxt *pc)
|
||||
{
|
||||
struct procfs_process *prc;
|
||||
|
||||
if (!pc)
|
||||
return;
|
||||
|
||||
DBG(CXT, ul_debugobj(pc, "deinit"));
|
||||
|
||||
prc = ul_path_get_dialect(pc);
|
||||
if (!prc)
|
||||
return;
|
||||
|
||||
free(prc);
|
||||
ul_path_set_dialect(pc, NULL, NULL);
|
||||
}
|
||||
|
||||
static ssize_t read_procfs_file(int fd, char *buf, size_t bufsz)
|
||||
{
|
||||
ssize_t sz = 0;
|
||||
size_t i;
|
||||
|
||||
if (fd < 0)
|
||||
return -EINVAL;
|
||||
|
||||
sz = read_all(fd, buf, bufsz);
|
||||
if (sz <= 0)
|
||||
return sz;
|
||||
|
||||
for (i = 0; i < (size_t) sz; i++) {
|
||||
if (buf[i] == '\0')
|
||||
buf[i] = ' ';
|
||||
}
|
||||
buf[sz - 1] = '\0';
|
||||
return sz;
|
||||
}
|
||||
|
||||
ssize_t procfs_process_get_cmdline(struct path_cxt *pc, char *buf, size_t bufsz)
|
||||
{
|
||||
int fd = ul_path_open(pc, O_RDONLY|O_CLOEXEC, "cmdline");
|
||||
|
||||
if (fd >= 0) {
|
||||
ssize_t sz = read_procfs_file(fd, buf, bufsz);
|
||||
close(fd);
|
||||
return sz;
|
||||
}
|
||||
return -errno;
|
||||
}
|
||||
|
||||
ssize_t procfs_process_get_cmdname(struct path_cxt *pc, char *buf, size_t bufsz)
|
||||
{
|
||||
int fd = ul_path_open(pc, O_RDONLY|O_CLOEXEC, "comm");
|
||||
|
||||
if (fd >= 0) {
|
||||
ssize_t sz = read_procfs_file(fd, buf, bufsz);
|
||||
close(fd);
|
||||
return sz;
|
||||
}
|
||||
return -errno;
|
||||
}
|
||||
|
||||
int procfs_process_get_uid(struct path_cxt *pc, uid_t *uid)
|
||||
{
|
||||
struct stat sb;
|
||||
int rc;
|
||||
|
||||
if ((rc = ul_path_stat(pc, &sb, NULL)) == 0)
|
||||
*uid = sb.st_uid;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns the next task TID, the @sub is automatically initialized
|
||||
* when called first time and closed after last call or you can
|
||||
* call closedir()* when you need to break the loop.
|
||||
*
|
||||
* Returns: <0 on error, 0 on success, >1 done
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* pid_t tid;
|
||||
* DIR *sub = NULL;
|
||||
* path_cxt *pc = ul_new_procfs_path(123, NULL);
|
||||
*
|
||||
* while (procfs_process_next_tid(pc, &sub, &tid) == 0)
|
||||
* printf("task: %d", (int) tid);
|
||||
*
|
||||
*/
|
||||
int procfs_process_next_tid(struct path_cxt *pc, DIR **sub, pid_t *tid)
|
||||
{
|
||||
struct dirent *d;
|
||||
|
||||
if (!pc || !sub || !tid)
|
||||
return -EINVAL;
|
||||
|
||||
if (!*sub) {
|
||||
*sub = ul_path_opendir(pc, "task");
|
||||
if (!*sub)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
while ((d = xreaddir(*sub))) {
|
||||
if (procfs_dirent_get_pid(d, tid) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
closedir(*sub);
|
||||
*sub = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int procfs_process_next_fd(struct path_cxt *pc, DIR **sub, int *fd)
|
||||
{
|
||||
struct dirent *d;
|
||||
|
||||
if (!pc || !sub || !fd)
|
||||
return -EINVAL;
|
||||
|
||||
if (!*sub) {
|
||||
*sub = ul_path_opendir(pc, "fd");
|
||||
if (!*sub)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
while ((d = xreaddir(*sub))) {
|
||||
uint64_t num;
|
||||
#ifdef _DIRENT_HAVE_D_TYPE
|
||||
if (d->d_type != DT_LNK && d->d_type != DT_UNKNOWN)
|
||||
continue;
|
||||
#endif
|
||||
if (ul_strtou64(d->d_name, &num, 10) < 0)
|
||||
continue;
|
||||
*fd = num;
|
||||
return 0;
|
||||
}
|
||||
|
||||
closedir(*sub);
|
||||
*sub = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple 'dirent' based stuff for use-cases where procfs_process_* API is overkill
|
||||
*/
|
||||
|
||||
/* stupid, but good enough as a basic filter */
|
||||
int procfs_dirent_is_process(struct dirent *d)
|
||||
{
|
||||
#ifdef _DIRENT_HAVE_D_TYPE
|
||||
if (d->d_type != DT_DIR && d->d_type != DT_UNKNOWN)
|
||||
return 0;
|
||||
#endif
|
||||
if (!isdigit((unsigned char) *d->d_name))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int procfs_dirent_get_pid(struct dirent *d, pid_t *pid)
|
||||
{
|
||||
uint64_t num;
|
||||
|
||||
if (!procfs_dirent_is_process(d))
|
||||
return -EINVAL;
|
||||
|
||||
if (ul_strtou64(d->d_name, &num, 10) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
*pid = (pid_t) num;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int procfs_dirent_get_uid(DIR *procfs, struct dirent *d, uid_t *uid)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (!procfs_dirent_is_process(d))
|
||||
return -EINVAL;
|
||||
|
||||
if (fstatat(dirfd(procfs), d->d_name, &st, 0))
|
||||
return -EINVAL;
|
||||
|
||||
*uid = st.st_uid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int procfs_dirent_match_uid(DIR *procfs, struct dirent *d, uid_t uid)
|
||||
{
|
||||
uid_t x;
|
||||
|
||||
if (procfs_dirent_get_uid(procfs, d, &x) == 0)
|
||||
return x == uid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* "name" of process; may be truncated, see prctl(2) and PR_SET_NAME.
|
||||
* The minimal of the @buf has to be 32 bytes. */
|
||||
int procfs_dirent_get_name(DIR *procfs, struct dirent *d, char *buf, size_t bufsz)
|
||||
{
|
||||
FILE *f;
|
||||
size_t sz;
|
||||
char tmp[1024], *p, *end = NULL;
|
||||
|
||||
if (bufsz < 32)
|
||||
return -EINVAL;
|
||||
if (!procfs_dirent_is_process(d))
|
||||
return -EINVAL;
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%s/stat", d->d_name);
|
||||
f = fopen_at(dirfd(procfs), tmp, O_CLOEXEC|O_RDONLY, "r");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
p = fgets(tmp, sizeof(tmp), f);
|
||||
fclose(f);
|
||||
if (!p)
|
||||
return -errno;
|
||||
|
||||
/* skip PID */
|
||||
while (*p && *p != '(')
|
||||
p++;
|
||||
|
||||
/* skip extra '(' */
|
||||
while (*p && *p == '(')
|
||||
p++;
|
||||
|
||||
end = p;
|
||||
while (*end && *end != ')')
|
||||
end++;
|
||||
|
||||
sz = end - p;
|
||||
if (sz > bufsz)
|
||||
sz = bufsz - 1;
|
||||
|
||||
memcpy(buf, p, sz);
|
||||
buf[sz] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int procfs_dirent_match_name(DIR *procfs, struct dirent *d, const char *name)
|
||||
{
|
||||
char buf[33];
|
||||
|
||||
if (procfs_dirent_get_name(procfs, d, buf, sizeof(buf)) == 0)
|
||||
return strcmp(name, buf) == 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* checks if fd is file in a procfs;
|
||||
* returns 1 if true, 0 if false or couldn't determine */
|
||||
int fd_is_procfs(int fd)
|
||||
{
|
||||
struct statfs st;
|
||||
int ret;
|
||||
|
||||
do {
|
||||
errno = 0;
|
||||
ret = fstatfs(fd, &st);
|
||||
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
return 0;
|
||||
xusleep(250000);
|
||||
}
|
||||
} while (ret != 0);
|
||||
|
||||
return st.f_type == STATFS_PROC_MAGIC;
|
||||
}
|
||||
|
||||
static char *strdup_procfs_file(pid_t pid, const char *name)
|
||||
{
|
||||
char buf[BUFSIZ];
|
||||
char *re = NULL;
|
||||
int fd;
|
||||
|
||||
snprintf(buf, sizeof(buf), _PATH_PROC "/%d/%s", (int) pid, name);
|
||||
fd = open(buf, O_CLOEXEC|O_RDONLY);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
if (read_procfs_file(fd, buf, sizeof(buf)) > 0)
|
||||
re = strdup(buf);
|
||||
close(fd);
|
||||
return re;
|
||||
}
|
||||
|
||||
char *pid_get_cmdname(pid_t pid)
|
||||
{
|
||||
return strdup_procfs_file(pid, "comm");
|
||||
}
|
||||
|
||||
char *pid_get_cmdline(pid_t pid)
|
||||
{
|
||||
return strdup_procfs_file(pid, "cmdline");
|
||||
}
|
||||
|
||||
#ifdef TEST_PROGRAM_PROCFS
|
||||
|
||||
static int test_tasks(int argc, char *argv[])
|
||||
{
|
||||
DIR *sub = NULL;
|
||||
struct path_cxt *pc;
|
||||
pid_t tid = 0, pid;
|
||||
|
||||
if (argc != 2)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
pid = strtol(argv[1], (char **) NULL, 10);
|
||||
printf("PID=%d, TIDs:", pid);
|
||||
|
||||
pc = ul_new_procfs_path(pid, NULL);
|
||||
if (!pc)
|
||||
err(EXIT_FAILURE, "alloc procfs handler failed");
|
||||
|
||||
while (procfs_process_next_tid(pc, &sub, &tid) == 0)
|
||||
printf(" %d", tid);
|
||||
|
||||
printf("\n");
|
||||
ul_unref_path(pc);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_fds(int argc, char *argv[])
|
||||
{
|
||||
DIR *sub = NULL;
|
||||
struct path_cxt *pc;
|
||||
pid_t pid;
|
||||
int fd = -1;
|
||||
|
||||
if (argc != 2)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
pid = strtol(argv[1], (char **) NULL, 10);
|
||||
printf("PID=%d, FDs:", pid);
|
||||
|
||||
pc = ul_new_procfs_path(pid, NULL);
|
||||
if (!pc)
|
||||
err(EXIT_FAILURE, "alloc procfs handler failed");
|
||||
|
||||
while (procfs_process_next_fd(pc, &sub, &fd) == 0)
|
||||
printf(" %d", fd);
|
||||
|
||||
fputc('\n', stdout);
|
||||
ul_unref_path(pc);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_processes(int argc, char *argv[])
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *d;
|
||||
char *name = NULL;
|
||||
uid_t uid = (uid_t) -1;
|
||||
char buf[128];
|
||||
|
||||
if (argc >= 3 && strcmp(argv[1], "--name") == 0)
|
||||
name = argv[2];
|
||||
if (argc >= 3 && strcmp(argv[1], "--uid") == 0)
|
||||
uid = (uid_t) atol(argv[2]);
|
||||
|
||||
dir = opendir(_PATH_PROC);
|
||||
if (!dir)
|
||||
err(EXIT_FAILURE, "cannot open proc");
|
||||
|
||||
while ((d = xreaddir(dir))) {
|
||||
pid_t pid = 0;
|
||||
|
||||
if (procfs_dirent_get_pid(d, &pid) != 0)
|
||||
continue;
|
||||
if (name && !procfs_dirent_match_name(dir, d, name))
|
||||
continue;
|
||||
if (uid != (uid_t) -1 && !procfs_dirent_match_uid(dir, d, uid))
|
||||
continue;
|
||||
procfs_dirent_get_name(dir, d, buf, sizeof(buf));
|
||||
printf(" %d [%s]", pid, buf);
|
||||
}
|
||||
|
||||
fputc('\n', stdout);
|
||||
closedir(dir);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_one_process(int argc, char *argv[])
|
||||
{
|
||||
pid_t pid;
|
||||
struct path_cxt *pc;
|
||||
char buf[BUFSIZ];
|
||||
uid_t uid = (uid_t) -1;
|
||||
|
||||
if (argc != 2)
|
||||
return EXIT_FAILURE;
|
||||
pid = strtol(argv[1], (char **) NULL, 10);
|
||||
|
||||
pc = ul_new_procfs_path(pid, NULL);
|
||||
if (!pc)
|
||||
err(EXIT_FAILURE, "cannot alloc procfs handler");
|
||||
|
||||
printf("%d\n", (int) pid);
|
||||
|
||||
procfs_process_get_uid(pc, &uid);
|
||||
printf(" UID: %zu\n", (size_t) uid);
|
||||
|
||||
procfs_process_get_cmdline(pc, buf, sizeof(buf));
|
||||
printf(" CMDLINE: '%s'\n", buf);
|
||||
|
||||
procfs_process_get_cmdname(pc, buf, sizeof(buf));
|
||||
printf(" COMM: '%s'\n", buf);
|
||||
|
||||
ul_unref_path(pc);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_isprocfs(int argc, char *argv[])
|
||||
{
|
||||
const char *name = argc > 1 ? argv[1] : "/proc";
|
||||
int fd = open(name, O_RDONLY);
|
||||
int is = 0;
|
||||
|
||||
if (fd >= 0) {
|
||||
is = fd_is_procfs(fd);
|
||||
close(fd);
|
||||
} else
|
||||
err(EXIT_FAILURE, "cannot open %s", name);
|
||||
|
||||
printf("%s: %s procfs\n", name, is ? "is" : "is NOT");
|
||||
return is ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage: %1$s --tasks <pid>\n"
|
||||
" %1$s --fds <pid>\n"
|
||||
" %1$s --is-procfs [<dir>]\n"
|
||||
" %1$s --processes [---name <name>] [--uid <uid>]\n"
|
||||
" %1$s --one <pid>\n",
|
||||
program_invocation_short_name);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "--tasks") == 0)
|
||||
return test_tasks(argc - 1, argv + 1);
|
||||
if (strcmp(argv[1], "--fds") == 0)
|
||||
return test_fds(argc - 1, argv + 1);
|
||||
if (strcmp(argv[1], "--processes") == 0)
|
||||
return test_processes(argc - 1, argv + 1);
|
||||
if (strcmp(argv[1], "--is-procfs") == 0)
|
||||
return test_isprocfs(argc - 1, argv + 1);
|
||||
if (strcmp(argv[1], "--one") == 0)
|
||||
return test_one_process(argc - 1, argv + 1);
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
#endif /* TEST_PROGRAM_PROCUTILS */
|
Loading…
Reference in New Issue