"Fossies" - the Fresh Open Source Software Archive

Member "chkrootkit-0.55/chkdirs.c" (8 Mar 2021, 7376 Bytes) of package /linux/misc/chkrootkit-0.55.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "chkdirs.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.53_vs_0.54.

    1 /* Copyright (C) Hal Pomeranz <hal@deer-run.com> and Deer Run Assoc, 2002/11/24
    2    All rights reserved.  Permission granted to freely redistribute and update
    3    as long as this Copyright notice is preserved.  No warranty expressed or
    4    implied.
    5 
    6    $Id: chkdirs.c,v 1.3 2003/01/20 19:44:13 hal Exp $
    7 
    8 
    9    Usage:     chkdirs [-n] dir ...
   10    Examples:  chkdirs /
   11               chkdirs -n /proc
   12    Recursively traverses one or more directories looking for discrepancies
   13    between the parent directory link count and the number of subdirectories
   14    (parent directory link count should always equal the number of subdirs
   15    plus two-- anything else indicates a "hidden" directory).  "-n" option
   16    means check directory but don't recursively descend into subdirectories.
   17 
   18   Changelog :
   19   2002/12/19 - Little port for *BSB and Solaris - Nelson Murilo
   20   2003/01/09 - More fix for Solaris - Nelson Murilo
   21   2003/01/14 - HP-UX patch - Gerard Breiner
   22   2003/01/20 - NAME_MAX Fix by Hal Pomeranz
   23   2003/09/01 - BSDI port by Nelson Murilo and Thomas Davidson
   24   2005/22/05 - APPLE test for limits.h included by Aaron Harwood
   25   2007/08/10 - strncpy used instead of strcpy - nm
   26   2007/12/24 - change `c' variable type - NIDE, Naoyuki
   27   2020/12/24 - Add a warning for btrfs (no inode usage)
   28 
   29 */
   30 
   31 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) || defined (hpux) || defined (__bsdi__) || defined (bsdi) || defined (__APPLE__)
   32 #include <limits.h>
   33 #elif defined(__APPLE__) && defined(__MACH__)
   34 #include <sys/syslimits.h>
   35 #endif
   36 
   37 #include <stdio.h>
   38 #include <stdlib.h>
   39 #include <sys/types.h>
   40 #include <sys/stat.h>
   41 #include <unistd.h>
   42 #include <dirent.h>
   43 #include <string.h>
   44 #include <errno.h>
   45 
   46 #ifndef NAME_MAX
   47 #define NAME_MAX        PATH_MAX
   48 #endif
   49 
   50 struct dirinfolist {
   51   char                   dil_name[NAME_MAX+1];
   52   int                    dil_lc;
   53   struct dirinfolist     *dil_next;
   54 };
   55 
   56 
   57 void usage ()
   58 {
   59   fprintf(stderr, "chkdirs [-n] dir ...\n");
   60   exit(255);
   61 }
   62 
   63 char *make_pathname (char *path, char *dir, char **buffer)
   64 {
   65   int plen, pathname_len, bufsize, offs;
   66   
   67   bufsize = 0; 
   68 
   69   plen = strlen(path);
   70   pathname_len = plen + strlen(dir) + 2;
   71 
   72   if (!(*buffer) || (sizeof(*buffer) < pathname_len)) {
   73     if (buffer) free((void *)*buffer);
   74     bufsize = (pathname_len > PATH_MAX) ? pathname_len : PATH_MAX;
   75     if (!(*buffer = (char *)malloc(bufsize))) {
   76       return((char *)NULL);
   77     }
   78   }
   79 
   80   if (dir[0] == '/') {   /* "dir" is absolute pathname, don't prepend "path" */
   81     offs = 0;
   82   }
   83   else {
   84     strncpy(*buffer, path, bufsize);
   85     if ((*buffer)[plen-1] == '/') {   /* "path" ends in "/", don't add extra */
   86       offs = plen;
   87     }
   88     else {
   89       (*buffer)[plen] = '/';
   90       offs = plen + 1;
   91     }
   92   }
   93   strncpy((*buffer)+offs, dir, bufsize - offs);
   94   return((*buffer));
   95 }
   96 
   97 int check_dir (char *dir, char *path, int linkcount, int norecurse)
   98 {
   99   int diff = -1;
  100   int plen, buflen, numdirs;
  101   char *curpath, *fullpath;
  102   DIR *dirhandle;
  103   struct dirent *finfo;
  104   struct dirinfolist *dl, *dptr;
  105   struct stat statinfo;
  106 
  107   /* When called recursively, "path" will be the full path of the cwd,
  108      but when called from main() "path" is empty.  We need the cwd path
  109      so we can chdir() back at the end of this routine, as well as when
  110      printing errors and other output.
  111   */
  112   if (!path || !(plen = strlen(path))) {
  113     buflen = PATH_MAX;
  114   retry:
  115     if (!(curpath = (char *)malloc(buflen))) {
  116       fprintf(stderr, "malloc() failed: %s\n", strerror(errno));
  117       return(-1);
  118     }
  119     if (!getcwd(curpath, buflen)) {
  120       if (errno == ERANGE) {
  121     free((void *)curpath);
  122     buflen = buflen * 2;
  123     goto retry;
  124       }
  125       else {
  126     fprintf(stderr, "getcwd() failed: %s\n", strerror(errno));
  127     return(-1);
  128       }
  129     }
  130   }
  131   else {             /* "path" is set, so just copy it into "curpath" */
  132     if (!(curpath = (char *)malloc(plen+1))) {
  133       fprintf(stderr, "malloc() failed: %s\n", strerror(errno));
  134       return(-1);
  135     }
  136     strncpy(curpath, path, plen+1);
  137   }
  138 
  139   /* Now set "fullpath" to be the absolute path name of the directory
  140      we will be checking (prepend "curpath" if "dir" is not already an
  141      absolute pathname).
  142   */
  143   fullpath = (char *)NULL;
  144   if (!make_pathname(curpath, dir, &fullpath)) {
  145     fprintf(stderr, "make_pathname() failed: %s\n", strerror(errno));
  146     free((void *)curpath);
  147     return(-1);
  148   }
  149 
  150   if (chdir(dir)) {
  151     fprintf(stderr, "chdir(%s): %s\n", fullpath, strerror(errno));
  152     free((void *)curpath);
  153     free((void *)fullpath);
  154     return(-1);
  155   }
  156 
  157   /* Again, "linkcount" (the link count of the current directory) is set
  158      only if check_dir() is called recursively.  Otherwise, we need to
  159      stat the directory ourselves.
  160   */
  161   if (!linkcount) {
  162     if (lstat(".", &statinfo)) {
  163       fprintf(stderr, "lstat(%s): %s\n", fullpath, strerror(errno));
  164       goto abort;
  165     }
  166     linkcount = statinfo.st_nlink;
  167     if (linkcount == 1) 
  168     {
  169        fprintf(stderr, "WARNIING: It seems you are using BTRFS, if this is true chkdirs can't help you to find hidden files/dirs\n"); 
  170        goto abort; 
  171      } 
  172   }
  173 
  174   if (!(dirhandle = opendir("."))) {
  175     fprintf(stderr, "opendir(%s): %s\n", fullpath, strerror(errno));
  176     goto abort;
  177   }
  178 
  179   numdirs = 0;
  180   dl = (struct dirinfolist *)NULL;
  181   while ((finfo = readdir(dirhandle))) {
  182     if (!strcmp(finfo->d_name, ".") || !strcmp(finfo->d_name, ".."))
  183       continue;
  184 
  185     if (lstat(finfo->d_name, &statinfo)) {
  186       fprintf(stderr, "lstat(%s/%s): %s\n",
  187           fullpath, finfo->d_name, strerror(errno));
  188       closedir(dirhandle);
  189       goto abort;
  190     }
  191 
  192     if (S_ISDIR(statinfo.st_mode)) {
  193       numdirs++;
  194 
  195       if (norecurse) continue;               /* just count subdirs if "-n" */
  196 
  197       /* Otherwise, keep a list of all directories found that have link
  198      count > 2 (indicating directory contains subdirectories).  We'll
  199      call check_dir() on each of these subdirectories in a moment...
  200       */
  201       if (statinfo.st_nlink > 2) {
  202     dptr = dl;
  203     if (!(dl = (struct dirinfolist *)malloc(sizeof(struct dirinfolist)))) {
  204       fprintf(stderr, "malloc() failed: %s\n", strerror(errno));
  205       norecurse = 1;
  206       while (dptr) {
  207         dl = dptr->dil_next;
  208         free((void *)dptr);
  209         dptr = dl;
  210       }
  211       continue;
  212     }
  213 
  214     strncpy(dl->dil_name, finfo->d_name, sizeof(dl->dil_name));
  215     dl->dil_lc = statinfo.st_nlink;
  216     dl->dil_next = dptr;
  217       }
  218     }
  219   }
  220   closedir(dirhandle);
  221 
  222   /* Parent directory link count had better equal #subdirs+2... */
  223   diff = linkcount - numdirs - 2;
  224   if (diff) printf("%d\t%s\n", diff, fullpath);
  225 
  226   /* Now check all subdirectories in turn... */
  227   while (dl) {
  228     check_dir(dl->dil_name, fullpath, dl->dil_lc, norecurse);
  229     dptr = dl->dil_next;
  230     free((void *)dl);
  231     dl = dptr;
  232   }
  233 
  234  abort:
  235   if (chdir(curpath)) {
  236     fprintf(stderr, "Final chdir(%s) failed (%s) -- EXIT!\n",
  237         curpath, strerror(errno));
  238     exit(255);
  239   }
  240   free((void *)fullpath);
  241   free((void *)curpath);
  242   return(diff);
  243 }
  244 
  245 
  246 int main (int argc, char **argv)
  247 {
  248   int norecurse = 0;
  249   int i, retval;
  250   int c;
  251 
  252   opterr = 0;
  253   while ((c = getopt(argc, argv, "n")) > 0) {
  254     switch (c) {
  255     case 'n':
  256       norecurse = 1;
  257       break;
  258     default:
  259       usage();
  260     }
  261   }
  262   if (argc <= optind) usage();
  263 
  264   for (i = optind; i < argc; i++) {
  265     retval = check_dir(argv[i], (char *)NULL, 0, norecurse);
  266   }
  267   exit(retval);
  268 }