diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 190 |
1 files changed, 190 insertions, 0 deletions
@@ -0,0 +1,190 @@ +/** + * Fd-enum is a simple tool to list open file descriptors of a pid by type + * Copyright (C) 2021 Aaron Ball <nullspoon@oper.io> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include <stdio.h> +#include <stdlib.h> +#include <dirent.h> +#include <unistd.h> +#include <string.h> +#include <sys/stat.h> + +struct config { + int pid; + char dead; + char live; + char sockets; + char inodes; + char pipes; + char showstats; +}; + +int fexists(char* path) { + FILE *fd = fopen(path, "r"); + if(!fd) + return 0; + fclose(fd); + return 1; +} + +void get_help() { + puts("Usage: \n\ + -d, --dead Print list of dead file descriptors (deleted but still open)\n\ + -i, --inodes Print list of inode file descriptors\n\ + -l, --live Print list of live file descriptors (open and existing)\n\ + -p, --pipes Print list of pipe file descriptors\n\ + -s, --sockets Print list of socket file descriptors\n\ +\n\ + -n, --no-stats Hide file descriptor statistics\n\ + -h, --help Print this help text\n\ +"); +} + +int parse_args(int argc, char* argv[], struct config* c) { + // Initialize config struct + c->pid = -1; + c->dead = 0; + c->live = 0; + c->sockets = 0; + c->pipes = 0; + c->inodes = 0; + c->showstats = 1; + int i = 1; + + while(i < argc) { + if(strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--dead") == 0) { + c->dead = 1; + } else if(strcmp(argv[i], "-l") == 0 || strcmp(argv[i], "--live") == 0) { + c->live = 1; + } else if(strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--sockets") == 0) { + c->sockets = 1; + } else if(strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--inodes") == 0) { + c->inodes = 1; + } else if(strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--pipes") == 0) { + c->pipes = 1; + } else if(strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--no-stats") == 0) { + c->showstats = 0; + } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { + get_help(); + exit(1); + } else { + c->pid = strtol(argv[i], NULL, 10); + } + + i++; + } + + if(c->pid == -1) { + fprintf(stderr, "Must specify valid pid\n"); + return 2; + } + return 0; +} + +int main(int argc, char* argv[]) { + struct config c; + + char pidpath_fd[32] = {'\0'}; + char fdpath[289] = {'\0'}; + char lnpath[512] = {'\0'}; + int retval = 0; + int len = 0; + unsigned long unknown = 0; + unsigned long dead = 0; + unsigned long live = 0; + unsigned long sockets = 0; + unsigned long inodes = 0; + unsigned long pipes = 0; + + struct stat sb; + + DIR *dp = NULL; + struct dirent *de = NULL; + + if(parse_args(argc, argv, &c) != 0) + return 1; + + // Construct the pid path + sprintf(pidpath_fd, "/proc/%d/fd", c.pid); + + dp = opendir(pidpath_fd); + while((de = readdir(dp)) != NULL) { + sprintf(fdpath, "%s/%s%c", pidpath_fd, de->d_name, '\0'); + + retval = stat(fdpath, &sb); + len = readlink(fdpath, lnpath, 512); + + if(len <= 0) + continue; + lnpath[len] = '\0'; + + // Sockets + if(S_ISSOCK(sb.st_mode)) { + sockets++; + if(c.sockets) + printf("%s -> %s\n", fdpath, lnpath); + + // Pipes + } else if(S_ISFIFO(sb.st_mode)) { + pipes++; + if(c.pipes) + printf("%s -> %s\n", fdpath, lnpath); + + // Char device links + } else if(S_ISCHR(sb.st_mode)) { + live++; + if(c.live) + printf("%s -> %s\n", fdpath, lnpath); + + // File desccriptors + } else if(S_ISREG(sb.st_mode) + || S_ISDIR(sb.st_mode)) { + // Exists + if(retval == 0 && fexists(lnpath)) { + live++; + if(c.live) + printf("%s -> %s\n", fdpath, lnpath); + + // Does not exist + } else { + dead++; + if(c.dead) + printf("%s -> %s\n", fdpath, lnpath); + } + + // Inodes + } else if(sb.st_mode == 384) { + inodes++; + if(c.inodes) + printf("%s -> %s\n", fdpath, lnpath); + + } else { + unknown++; + } + } + closedir(dp); + + if(c.showstats) { + printf("dead: %ld\n", dead); + printf("live: %ld\n", live); + printf("sockets: %ld\n", sockets); + printf("anon_inodes: %ld\n", inodes); + printf("pipes: %ld\n", pipes); + printf("unknown: %ld\n", unknown); + } + + return 0; +} |