summaryrefslogtreecommitdiff
path: root/main.c
blob: 1921e14e26f287b5193805885879c26878f55cca (plain)
    1 /**
    2  * Fd-enum is a simple tool to list open file descriptors of a pid by type
    3  * Copyright (C) 2021  Aaron Ball <nullspoon@oper.io>
    4  * 
    5  * This program is free software: you can redistribute it and/or modify
    6  * it under the terms of the GNU General Public License as published by
    7  * the Free Software Foundation, either version 3 of the License, or
    8  * (at your option) any later version.
    9  * 
   10  * This program is distributed in the hope that it will be useful,
   11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13  * GNU General Public License for more details.
   14  * 
   15  * You should have received a copy of the GNU General Public License
   16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   17  */
   18 #include <stdio.h>
   19 #include <stdlib.h>
   20 #include <dirent.h>
   21 #include <unistd.h>
   22 #include <string.h>
   23 #include <sys/stat.h>
   24 
   25 struct config {
   26   int pid;
   27   char dead;
   28   char live;
   29   char sockets;
   30   char inodes;
   31   char pipes;
   32   char showstats;
   33 };
   34 
   35 int fexists(char* path) {
   36   FILE *fd = fopen(path, "r");
   37   if(!fd)
   38     return 0;
   39   fclose(fd);
   40   return 1;
   41 }
   42 
   43 void get_help() {
   44   puts("Usage: \n\
   45   -d, --dead     Print list of dead file descriptors (deleted but still open)\n\
   46   -i, --inodes   Print list of inode file descriptors\n\
   47   -l, --live     Print list of live file descriptors (open and existing)\n\
   48   -p, --pipes    Print list of pipe file descriptors\n\
   49   -s, --sockets  Print list of socket file descriptors\n\
   50 \n\
   51   -n, --no-stats Hide file descriptor statistics\n\
   52   -h, --help     Print this help text\n\
   53 ");
   54 }
   55 
   56 int parse_args(int argc, char* argv[], struct config* c) {
   57   // Initialize config struct
   58   c->pid       = -1;
   59   c->dead      = 0;
   60   c->live      = 0;
   61   c->sockets   = 0;
   62   c->pipes     = 0;
   63   c->inodes    = 0;
   64   c->showstats = 1;
   65   int i = 1;
   66 
   67   while(i < argc) {
   68     if(strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--dead") == 0) {
   69       c->dead = 1;
   70     } else if(strcmp(argv[i], "-l") == 0 || strcmp(argv[i], "--live") == 0) {
   71       c->live = 1;
   72     } else if(strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--sockets") == 0) {
   73       c->sockets = 1;
   74     } else if(strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--inodes") == 0) {
   75       c->inodes = 1;
   76     } else if(strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--pipes") == 0) {
   77       c->pipes = 1;
   78     } else if(strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--no-stats") == 0) {
   79       c->showstats = 0;
   80     } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
   81       get_help();
   82       exit(1);
   83     } else {
   84       c->pid = strtol(argv[i], NULL, 10);
   85     }
   86 
   87     i++;
   88   }
   89 
   90   if(c->pid == -1) {
   91     fprintf(stderr, "Must specify valid pid\n");
   92     return 2;
   93   }
   94   return 0;
   95 }
   96 
   97 int main(int argc, char* argv[]) {
   98   struct config c;
   99 
  100   char pidpath_fd[32] = {'\0'};
  101   char fdpath[289]    = {'\0'};
  102   char lnpath[512]    = {'\0'};
  103   int retval = 0;
  104   int len    = 0;
  105   unsigned long unknown  = 0;
  106   unsigned long dead    = 0;
  107   unsigned long live    = 0;
  108   unsigned long sockets = 0;
  109   unsigned long inodes  = 0;
  110   unsigned long pipes   = 0;
  111 
  112   struct stat sb;
  113 
  114   DIR *dp = NULL;
  115   struct dirent *de = NULL;
  116 
  117   if(parse_args(argc, argv, &c) != 0)
  118     return 1;
  119 
  120   // Construct the pid path
  121   sprintf(pidpath_fd, "/proc/%d/fd", c.pid);
  122 
  123   dp = opendir(pidpath_fd);
  124   while((de = readdir(dp)) != NULL) {
  125     sprintf(fdpath, "%s/%s%c", pidpath_fd, de->d_name, '\0');
  126 
  127     retval = stat(fdpath, &sb);
  128     len = readlink(fdpath, lnpath, 512);
  129 
  130     if(len <= 0)
  131       continue;
  132     lnpath[len] = '\0';
  133 
  134     // Sockets
  135     if(S_ISSOCK(sb.st_mode)) {
  136       sockets++;
  137       if(c.sockets)
  138         printf("%s -> %s\n", fdpath, lnpath);
  139 
  140     // Pipes
  141     } else if(S_ISFIFO(sb.st_mode)) {
  142       pipes++;
  143       if(c.pipes)
  144         printf("%s -> %s\n", fdpath, lnpath);
  145 
  146     // Char device links
  147     } else if(S_ISCHR(sb.st_mode)) {
  148       live++;
  149       if(c.live)
  150         printf("%s -> %s\n", fdpath, lnpath);
  151 
  152     // File desccriptors
  153     } else if(S_ISREG(sb.st_mode)
  154         || S_ISDIR(sb.st_mode)) {
  155       // Exists
  156       if(retval == 0 && fexists(lnpath)) {
  157         live++;
  158         if(c.live)
  159           printf("%s -> %s\n", fdpath, lnpath);
  160 
  161       // Does not exist
  162       } else {
  163         dead++;
  164         if(c.dead)
  165           printf("%s -> %s\n", fdpath, lnpath);
  166       }
  167 
  168     // Inodes
  169     } else if(sb.st_mode == 384) {
  170       inodes++;
  171       if(c.inodes)
  172         printf("%s -> %s\n", fdpath, lnpath);
  173 
  174     } else {
  175       unknown++;
  176     }
  177   }
  178   closedir(dp);
  179 
  180   if(c.showstats) {
  181     printf("dead:        %ld\n", dead);
  182     printf("live:        %ld\n", live);
  183     printf("sockets:     %ld\n", sockets);
  184     printf("anon_inodes: %ld\n", inodes);
  185     printf("pipes:       %ld\n", pipes);
  186     printf("unknown:     %ld\n", unknown);
  187   }
  188 
  189   return 0;
  190 }

Generated by cgit