[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Program to find files which are not part of packages.



OK, a lot of people wanted the program to find files which do not belong
to packages currently installed in the system... so I have included it
as an attachment. If it turns into something useful, I will release it as
a Debian package, but just now I see it as more as a producer of interesting
results. Please do not feed the output directly into "rm"! For instance,
/etc/passwd is not owned by any package. Deleting this might be considered
bad!

Please feel free to make changes to the code. If they are good, mail me them
back and I will add them into the program. It is in c++, and as it is so small
I have also included the executable...

G.

PS. You have to feed in the filenames you want to check on stdin. I couldn't
    be bothered writing my own recursive find program, so I wrote it to
    use the standard "find". E.g.

    find /etc -xdev -print | ./dpkg-eliminate
    Questionable files appear on stdout, and diagnostics on stderr. Make sure
    that the filenames are absolute (beginning with /).

    Enjoy!!

-- 
Gordon Russell
http://www.dcs.napier.ac.uk/~gor
PGP Public Key - http://www.dcs.napier.ac.uk/~gor/pgpkey.txt
#include <iostream.h>
#include <stdlib.h>
#include <unistd.h>
#include <fstream.h>
#include <sys/types.h>
#include <dirent.h>
#include <search.h>
#include <string.h>

//
// Name:   dpkg-eliminate
// Author: Gordon Russell <gor@debian.org>
// Version: 0.1
//
// A program to scan for file which exist in system directories which
// are not owned by packages installed in the system.
//
// The program reads stdin for filenames seperated by returns, and then
// searches the database looking for a package to which it belongs. If the
// file does not belong to a package, it is printed on stdout.
//
// It is intended that this program will eventually produce a list of
// files which are candidates for deletion. Please feel free to make changes.
// If it is a useful change, why not send me it, and I will include it in the
// next release! It may even become a Debian package!!
//
// Diagnostic messages are printed on stderr.
//
// One way to run this program is using find, eg:
// #  find /etc -xdev -print | dpkg-eliminate
//
//
// Changelog:
//    0.1 : 29th Oct 1998 - Gordon Russell <g.russell@dcs.napier.ac.uk>
//          First release. Program takes into account only packages contained
//          in *.list files in dpkg directory, diversions, and alternatives.
//

#define DPKG_LOC "/var/lib/dpkg/info"
#define ALT_LOC "/var/lib/dpkg/alternatives"
#define DIV_LOC "/var/lib/dpkg/diversions"

#define HASH_ESTIMATE 100000

typedef struct {
  char *package;
  char *filename;
} PACKAGE_FILE;

// The package files are stored in an array. I tried a hashing table, but
// the performance stank.
PACKAGE_FILE **sorted_list=NULL;
int package_entries=0;

// Create the package file storage space.
//
void create_store(int max_size)
{
  sorted_list = new (PACKAGE_FILE *)[max_size];
  package_entries = 0;
}

// Add an entry to the storage space
//
void add_entry(PACKAGE_FILE *entry)
{
  sorted_list[package_entries++] = entry;
  if (package_entries >= HASH_ESTIMATE) { // Shit!
    cerr << "I can handle only " << HASH_ESTIMATE << " files, sorry!" << endl;
    exit(1);
  }
}

// A Quick way to add an entry
//
void add_details(char *name,char *package)
{
  PACKAGE_FILE *pdata;
  pdata = new PACKAGE_FILE;
  pdata->filename = name;
  pdata->package  = package;
  add_entry(pdata);
}

// For sorting and searching, we need a comparison function for the storage
// space.
//
int package_compare(const void *left,const void *right) {
  PACKAGE_FILE *pleft = *(PACKAGE_FILE **)left; 
  PACKAGE_FILE *pright= *(PACKAGE_FILE **)right;
  return strcmp(pleft->filename,pright->filename);
}

// Find the package details given the filename
//
int locate(char *name) {
  PACKAGE_FILE *e;
  PACKAGE_FILE look;
  look.filename = name;
  e = &look;
  e = (PACKAGE_FILE *)bsearch(&e,sorted_list,package_entries,
                      sizeof(PACKAGE_FILE *), package_compare);
  if (e) {
    return (((unsigned int)e - (unsigned int)sorted_list))
           /sizeof(PACKAGE_FILE *);
  } else {
    return -1;
  }
}

// Sort the package store so that we can use binary search later.
//
void finalise_entries()
{
  cerr << "Sorting the list..." << endl;
  qsort(sorted_list,package_entries,sizeof(PACKAGE_FILE *),package_compare);
}

// Add in package file diversions. I guessed at the format of the diversions
// file. Hope I was right!
//
void build_diversions() {
  ifstream listfile(DIV_LOC,ios::in);
  if (listfile.fail()) {
    cerr << "Cannot read diversions file" << endl;
    exit(1);
  }
  while (!listfile.eof()) {
    char nfrom[256],nto[256],npack[256];
    listfile.getline(nfrom,256);
    listfile.getline(nto,256);
    listfile.getline(npack,256);
    if (strcmp(nfrom,"")!=0) {
      // cerr << "Added diversion " << nfrom << " -> " << nto ;
      // cerr << " (" << npack << ")" << endl;
      add_details(strdup(nto),strdup(npack));
    }
  }
  listfile.close();
}

// Add in package file alternatives. I guessed at the format of this info.
// Hope I was right!
//
void build_alternatives() {
  DIR *dir = opendir(ALT_LOC);
  if(dir == NULL) {
    cerr << "Error opening the alternatives list directory" << endl;
    exit(1);
  }
  struct dirent *entry;
  do {
    entry = readdir(dir);
    if (entry) {
      int len = strlen(entry->d_name);
      char *pname = "/etc/alternatives";
      char namebuf[256];
      strcpy(namebuf,ALT_LOC);
      strcat(namebuf,"/");
      strcat(namebuf,entry->d_name);
      ifstream listfile(namebuf,ios::in);
      if (listfile.fail()) {
        cerr << "Listfile " << entry->d_name << " exists but cannot be ";
        cerr << "opened!" << endl;
        exit(1);
      } else {
        char intbuf[256];
        strcpy(intbuf,"/etc/alternatives/");
        strcat(intbuf,entry->d_name);
        char *name = strdup(intbuf);
        add_details(name,pname);
      }
      int lineno=0;
      while (!listfile.eof()) {
        char file[256];
        listfile.getline(file,256);
        if (strcmp(file,"")==0) break;
        if (lineno>0) {
          char *name;
          if (file[0] == '/') {
            name = strdup(file);
          } else {
            char intbuf[256];
            strcpy(intbuf,"/etc/alternatives/");
            strcat(intbuf,file);
            name = strdup(intbuf);
          }
          // cerr << "Added " << name << endl;
          add_details(name,pname);
        }
        lineno++;
      }
      listfile.close();
    }
  } while (entry);
  closedir(dir);
}

// Add in the details from all the .list files for every installed package.
//
void build_search() {
  int added = 0;
  DIR *dir = opendir(DPKG_LOC);
  if(dir == NULL) {
    cerr << "Error opening the dpkg list directory" << endl;
    exit(1);
  }
  create_store(HASH_ESTIMATE);
  struct dirent *entry;
  do {
    entry = readdir(dir);
    if (entry) {
      int len = strlen(entry->d_name);
      if (len > 5) {
        if ( strcmp((entry->d_name+len-5),".list")==0 ) {
          // cout << "Package list file " << entry->d_name << endl;
          char *pname = strdup(entry->d_name);
          pname[len-5-1]='\0';
          char namebuf[256];
          strcpy(namebuf,DPKG_LOC);
          strcat(namebuf,"/");
          strcat(namebuf,entry->d_name);
          ifstream listfile(namebuf,ios::in);
          if (listfile.fail()) {
            cerr << "Listfile " << entry->d_name << " exists but cannot be ";
            cerr << "opened!" << endl;
            exit(1);
          }
          while (!listfile.eof()) {
            char file[256];
            listfile.getline(file,256);
            if ( (strcmp(file,"/.")!=0) && (strcmp(file,"")!=0) ) {
              if ((added%1000)==0) cerr << "+";
              added++;
              add_details(strdup(file),pname);
            }
         }
         listfile.close();
        }
      }
    }
  } while (entry);
  closedir(dir);
  cerr << endl;
  cerr << " " << added << " files in system reported to belong to packages" ;
  cerr << endl;
}

//
// Do the work.
//
main()
{
  cerr << "Adding package lists" << endl;
  build_search();
  cerr << "Adding alternatives" << endl;
  build_alternatives();
  cerr << "Adding diversions" << endl;
  build_diversions();
  finalise_entries();
  char buffer[1024];
  while (!cin.eof()) {
    cin.getline(buffer,1024);
    if (strcmp(buffer,"")!=0) {
      int pos = locate(buffer);
      if (pos <0) {
        cout << "File " << buffer << " is not part of a package" << endl;
      }
    }
  }
}

Attachment: dpkg-eliminate.gz
Description: Binary data


Reply to: