]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - lib/procutils.c
scriptreplay: check for EOF
[thirdparty/util-linux.git] / lib / procutils.c
index 2ab322522f7a01e0e1cb559b0ed9a54ca71688e7..8fb5d5c00d7c2d512f96484082923263f4bf4dde 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <dirent.h>
 #include <ctype.h>
 
 #include "procutils.h"
+#include "fileutils.h"
+#include "all-io.h"
 #include "c.h"
 
 /*
@@ -73,7 +76,7 @@ int proc_next_tid(struct proc_tasks *tasks, pid_t *tid)
        char *end;
 
        if (!tasks || !tid)
-               return -1;
+               return -EINVAL;
 
        *tid = 0;
        errno = 0;
@@ -85,7 +88,7 @@ int proc_next_tid(struct proc_tasks *tasks, pid_t *tid)
 
                if (!isdigit((unsigned char) *d->d_name))
                        continue;
-
+               errno = 0;
                *tid = (pid_t) strtol(d->d_name, &end, 10);
                if (errno || d->d_name == end || (end && *end))
                        return -1;
@@ -95,19 +98,158 @@ int proc_next_tid(struct proc_tasks *tasks, pid_t *tid)
        return 0;
 }
 
-#ifdef TEST_PROGRAM
+/* returns process command path, use free() for result */
+static char *proc_file_strdup(pid_t pid, const char *name)
+{
+       char buf[BUFSIZ], *res = NULL;
+       ssize_t sz = 0;
+       size_t i;
+       int fd;
 
-#include "c.h"
+       snprintf(buf, sizeof(buf), "/proc/%d/%s", (int) pid, name);
+       fd = open(buf, O_RDONLY);
+       if (fd < 0)
+               goto done;
 
-int main(int argc, char *argv[])
+       sz = read_all(fd, buf, sizeof(buf));
+       if (sz <= 0)
+               goto done;
+
+       for (i = 0; i < (size_t) sz; i++) {
+
+               if (buf[i] == '\0')
+                       buf[i] = ' ';
+       }
+       buf[sz - 1] = '\0';
+       res = strdup(buf);
+done:
+       if (fd >= 0)
+               close(fd);
+       return res;
+}
+
+/* returns process command path, use free() for result */
+char *proc_get_command(pid_t pid)
+{
+       return proc_file_strdup(pid, "cmdline");
+}
+
+/* returns process command name, use free() for result */
+char *proc_get_command_name(pid_t pid)
+{
+       return proc_file_strdup(pid, "comm");
+}
+
+struct proc_processes *proc_open_processes(void)
+{
+       struct proc_processes *ps;
+
+       ps = calloc(1, sizeof(struct proc_processes));
+       if (ps) {
+               ps->dir = opendir("/proc");
+               if (ps->dir)
+                       return ps;
+       }
+
+       free(ps);
+       return NULL;
+}
+
+void proc_close_processes(struct proc_processes *ps)
+{
+       if (ps && ps->dir)
+               closedir(ps->dir);
+       free(ps);
+}
+
+void proc_processes_filter_by_name(struct proc_processes *ps, const char *name)
+{
+       ps->fltr_name = name;
+       ps->has_fltr_name = name ? 1 : 0;
+}
+
+void proc_processes_filter_by_uid(struct proc_processes *ps, uid_t uid)
+{
+       ps->fltr_uid = uid;
+       ps->has_fltr_uid = 1;
+}
+
+int proc_next_pid(struct proc_processes *ps, pid_t *pid)
+{
+       struct dirent *d;
+
+       if (!ps || !pid)
+               return -EINVAL;
+
+       *pid = 0;
+       errno = 0;
+
+       do {
+               char buf[BUFSIZ], *p;
+
+               errno = 0;
+               d = readdir(ps->dir);
+               if (!d)
+                       return errno ? -1 : 1;          /* error or end-of-dir */
+
+
+               if (!isdigit((unsigned char) *d->d_name))
+                       continue;
+
+               /* filter out by UID */
+               if (ps->has_fltr_uid) {
+                       struct stat st;
+
+                       if (fstatat(dirfd(ps->dir), d->d_name, &st, 0))
+                               continue;
+                       if (ps->fltr_uid != st.st_uid)
+                               continue;
+               }
+
+               /* filter out by NAME */
+               if (ps->has_fltr_name) {
+                       char procname[256];
+                       FILE *f;
+
+                       snprintf(buf, sizeof(buf), "%s/stat", d->d_name);
+                       f = fopen_at(dirfd(ps->dir), buf, O_CLOEXEC|O_RDONLY, "r");
+                       if (!f)
+                               continue;
+
+                       p = fgets(buf, sizeof(buf), f);
+                       fclose(f);
+                       if (!p)
+                               continue;
+
+                       if (sscanf(buf, "%*d (%255[^)])", procname) != 1)
+                               continue;
+
+                       /* ok, we got the process name. */
+                       if (strcmp(procname, ps->fltr_name) != 0)
+                               continue;
+               }
+
+               p = NULL;
+               errno = 0;
+               *pid = (pid_t) strtol(d->d_name, &p, 10);
+               if (errno || d->d_name == p || (p && *p))
+                       return errno ? -errno : -1;
+
+               return 0;
+       } while (1);
+
+       return 0;
+}
+
+#ifdef TEST_PROGRAM_PROCUTILS
+
+static int test_tasks(int argc, char *argv[])
 {
        pid_t tid, pid;
        struct proc_tasks *ts;
 
-       if (argc != 2) {
-               fprintf(stderr, "usage: %s <pid>\n", argv[0]);
+       if (argc != 2)
                return EXIT_FAILURE;
-       }
 
        pid = strtol(argv[1], (char **) NULL, 10);
        printf("PID=%d, TIDs:", pid);
@@ -123,4 +265,44 @@ int main(int argc, char *argv[])
         proc_close_tasks(ts);
        return EXIT_SUCCESS;
 }
-#endif /* TEST_PROGRAM */
+
+static int test_processes(int argc, char *argv[])
+{
+       pid_t pid;
+       struct proc_processes *ps;
+
+       ps = proc_open_processes();
+       if (!ps)
+               err(EXIT_FAILURE, "open list of processes failed");
+
+       if (argc >= 3 && strcmp(argv[1], "--name") == 0)
+               proc_processes_filter_by_name(ps, argv[2]);
+
+       if (argc >= 3 && strcmp(argv[1], "--uid") == 0)
+               proc_processes_filter_by_uid(ps, (uid_t) atol(argv[2]));
+
+       while (proc_next_pid(ps, &pid) == 0)
+               printf(" %d", pid);
+
+       printf("\n");
+        proc_close_processes(ps);
+       return EXIT_SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+       if (argc < 2) {
+               fprintf(stderr, "usage: %1$s --tasks <pid>\n"
+                               "       %1$s --processes [---name <name>] [--uid <uid>]\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], "--processes") == 0)
+               return test_processes(argc - 1, argv + 1);
+
+       return EXIT_FAILURE;
+}
+#endif /* TEST_PROGRAM_PROCUTILS */