Logo Search packages:      
Sourcecode: deborphan version File versions

deborphan.c

/* deborphan - Find orphaned libraries on a Debian system.
   Copyright (C) 2000, 2001, 2002, 2003 Cris van Pelt
   Copyright (C) 2003, 2004 Peter Palfrader

   $Id: deborphan.c 511 2005-03-16 14:52:39Z weasel $

   Distributed under the terms of the Artistic License.
*/

/* Header files we should all have. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <deborphan.h>
#include <set.h>

#ifdef HAVE_ERRNO_H
#  include <errno.h>
#endif

/* These files should already be installed on the host machine - 
   the GPL does not allow redistribution in this package. */
#ifdef ENABLE_NLS
#  include <libintl.h>
#  include <locale.h>
#endif

#ifdef USE_XALLOC
#  include <xalloc.h>
#endif

/* Use either getopt.h (getopt_long) or unistd.h (getopt) */
#ifdef HAVE_GETOPT_H
#  include <getopt.h>
#else
#  include <unistd.h>
extern int optind;
#endif

/* Name this program was called with. */
char *program_name;

/* Options given on the commandline */
int options[NUM_OPTIONS];

/* An optional list of packages to search for. */
char **search_for;

/* A bunch of packages to keep. */
dep *keep;

static int depcmp(const dep* d1, const dep* d2)
{
      return strcmp(d1->name, d2->name);
}

int
main(int argc, char *argv[])
{
    char *line, *sfile = NULL, *kfile = NULL;
#ifdef LOW_MEM
    FILE *sfile_content;
#else
    char *sfile_content, *sfile_content2;
#endif
    pkg_info *package, *this;
    int i, argind;
    int exclude_list_cnt = 0;
    int exclude_list_max = 0;
    dep *exclude_list = NULL;

    struct option longopts[] = {
      {"version", 0, 0, 'v'},
      {"help", 0, 0, 'h'},
      {"status-file", 1, 0, 'f'},
      {"show-deps", 0, 0, 'd'},
      {"nice-mode", 0, 0, 'n'},
      {"all-packages", 0, 0, 'a'},
      {"priority", 1, 0, 'p'},
      {"show-section", 0, 0, 's'},
      {"no-show-section", 0, 0, 0},
      {"show-priority", 0, 0, 'P'},
      {"show-size", 0, 0, 'z'},
      {"force-hold", 0, 0, 'H'},
      {"keep-file", 1, 0, 'k'},
      {"add-keep", 0, 0, 'A'},
      {"del-keep", 0, 0, 'R'},
      {"list-keep", 0, 0, 'L'},
      {"zero-keep", 0, 0, 'Z'},
      {"guess-dev", 0, 0, 1},
      {"guess-perl", 0, 0, 2},
      {"guess-section", 0, 0, 3},
      {"guess-all", 0, 0, 4},
      {"guess-debug", 0, 0, 5},
#ifdef DEBFOSTER_KEEP
      {"df-keep", 0, 0, 6},
#endif
      {"guess-only", 0, 0, 7},
#ifdef DEBFOSTER_KEEP
      {"no-df-keep", 0, 0, 8},
#endif
      {"guess-pike", 0, 0, 9},
      {"guess-python", 0, 0, 10},
      {"guess-ruby", 0, 0, 11},
      {"guess-interpreters", 0, 0, 12},
      {"guess-dummy", 0, 0, 13},
      {"guess-common", 0, 0, 14},
      {"guess-data", 0, 0, 15},
      {"guess-doc", 0, 0, 16},
      {"find-config", 0, 0, 17},
      {"libdevel", 0, 0, 18},
      {"exclude", 1, 0, 'e'},
      {0, 0, 0, 0}
    };

    program_name = argv[0];
    memset(options, 0, NUM_OPTIONS * sizeof(int));

    options[PRIORITY] = DEFAULT_PRIORITY;
#ifdef IGNORE_DEBFOSTER
    options[NO_DEBFOSTER] = 1;
#endif


#ifdef ENABLE_NLS
    setlocale(LC_ALL, "");
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    while ((i = _get_opt(argc, argv, "p:advhe:nf:sPzHk:ARLZ", 
                   longopts, NULL)) != EOF) {
      switch (i) {
      case 'd':
          options[SHOW_DEPS] = 1;
          break;
      case 'h':
          exit_help();
          break;
      case 'v':
          exit_version();
          break;
      case 'f':
          sfile = (char *) xmalloc((strlen(optarg) + 1) * sizeof(sfile));
          strcpy(sfile, optarg);
          break;
      case 'n':
          options[NICE_MODE] = 1;
          break;
      case 'a':
          options[ALL_PACKAGES] = 1;
#ifdef ALL_PACKAGES_IMPLY_SECTION
          options[SHOW_SECTION]++;
#endif
          break;
      case 'p':
          options[PRIORITY] = string_to_priority(optarg);
          if (!options[PRIORITY]) {
            if (!sscanf(optarg, "%d", &options[PRIORITY])) {
                print_usage(stderr);
                error(EXIT_FAILURE, 0, "invalid priority: %s", optarg);
            }
          }
          break;
      case 's':
          options[SHOW_SECTION]++;
          break;
      case 0:
          options[SHOW_SECTION]--;
          break;
      case 'P':
          options[SHOW_PRIORITY] = 1;
          break;
      case 'z':
          options[SHOW_SIZE] = 1;
          break;
      case 'H':
          options[FORCE_HOLD] = 1;
          break;
      case 'k':
          kfile = optarg;
          break;
      case 'A':
          options[ADD_KEEP] = 1;
          break;
      case 'R':
          options[DEL_KEEP] = 1;
          break;
      case 'L':
          options[LIST_KEEP] = 1;
          break;
      case 'Z':
            options[ZERO_KEEP] = 1;
            break;
      case 1:
          guess_set(GUESS_DEV);
          break;
      case 2:
          guess_set(GUESS_PERL);
          break;
      case 3:
          guess_set(GUESS_SECTION);
          break;
      case 4:
          guess_set(GUESS_ALL);
          break;
      case 5:
          guess_set(GUESS_DEBUG);
          break;
#ifdef DEBFOSTER_KEEP
      case 6:
          options[NO_DEBFOSTER] = 0;
          break;
#endif
      case 7:
          options[GUESS_ONLY] = 1;
          break;
#ifdef DEBFOSTER_KEEP
      case 8:
          options[NO_DEBFOSTER] = 1;
          break;
#endif
      case 9:
          guess_set(GUESS_PIKE);
          break;
      case 10:
          guess_set(GUESS_PYTHON);
          break;
      case 11:
          guess_set(GUESS_RUBY);
          break;
      case 12:
          guess_set(GUESS_IP);
          break;
      case 13:
          guess_set(GUESS_DUMMY);
          break;
      case 14:
          guess_set(GUESS_COMMON);
          break;
      case 15:
          guess_set(GUESS_DATA);
          break;
      case 16:
          guess_set(GUESS_DOC);
          break;
      case 17:
          options[FIND_CONFIG] = 1;
          options[ALL_PACKAGES] = 1;
          break;
      case 18:
          options[SEARCH_LIBDEVEL] = 1;
          break;
      case 'e':
          while ( optarg ) {
                char *c_ptr;
                if ( exclude_list_cnt >= exclude_list_max ) {
                  /* grow exclude_list[] array */
                  exclude_list_max = exclude_list_max ? exclude_list_max*2 : INIT_EXCLUDES_COUNT;
#ifdef DEBUG
                  fprintf(stderr, "Growing excludes field to %d.\n", exclude_list_max);
                  fflush(stderr);
#endif /* DEBUG */
                  exclude_list = xrealloc( exclude_list, exclude_list_max * sizeof(exclude_list[0]) );
                }
                if ( exclude_list_cnt >= exclude_list_max )
                      error(EXIT_FAILURE, 0, "Too many exclude packages");
                c_ptr = strsep(&optarg, ",");
                exclude_list[ exclude_list_cnt ].name = c_ptr;
                exclude_list[ exclude_list_cnt ].namehash = strhash(c_ptr);
                ++exclude_list_cnt;
          }
          qsort(exclude_list, exclude_list_cnt, sizeof(exclude_list[0]),
                      (int(*)(const void*, const void*))depcmp);
          break;
      case '?':
          print_usage(stderr);
          exit(EXIT_FAILURE);
          break;
      }
    }
#ifdef DEFAULT_NICE           /* Invert the value of nice_mode */
   options[NICE_MODE] ^= 1;
#endif

   if (options[ZERO_KEEP]) {
      if (!kfile)
          kfile = KEEPER_FILE;
      if (zerokeep(kfile) < 0)
          error(EXIT_FAILURE, errno, "%s", kfile);

      /* Don't always exit. "deborphan -Z -A <foo>" should be valid. */
      if (!options[ADD_KEEP])
            exit(EXIT_SUCCESS);
   }
   
   if (options[LIST_KEEP]) {
       if (!kfile)
         kfile = KEEPER_FILE;
       
       if (!listkeep(kfile)) {
#ifndef DEBFOSTER_KEEP
         if (errno != ENOENT) /* If the file doesn't exit, we just have an empty list */
             error(EXIT_FAILURE, errno, "%s", kfile); /* fatal */
#else
         error(0, errno, "%s", kfile); /* non-fatal */
#endif
       }
#ifdef DEBFOSTER_KEEP
       if (!options[NO_DEBFOSTER]) {
         fprintf(stderr, "-- %s -- \n", DEBFOSTER_KEEP);
         listkeep(DEBFOSTER_KEEP);
       }
#endif
       exit(EXIT_SUCCESS);
   }

   if (options[GUESS_ONLY] && !options[GUESS]) {
       print_usage(stderr);
       error(EXIT_FAILURE, 0, "need at least one other --guess option.");
   }

    argind = optind;
    i = 0;
    if (kfile == NULL)
      kfile = KEEPER_FILE;
    if (sfile == NULL)
      sfile = STATUS_FILE;

    if ((argc - argind) > 50)
      error(EXIT_FAILURE, E2BIG, "");

    if (argind < argc) {
      options[SEARCH] = 1;
      options[ALL_PACKAGES] = 1;
      options[SHOW_DEPS] = 1;
      options[PRIORITY] = 0;
    }

    keep = readkeep(kfile);

    if (options[ADD_KEEP] || options[DEL_KEEP]) {
      char **args;
      if (argind >= argc)
          error(EXIT_FAILURE, 0, "not enough arguments for %s.",
              options[ADD_KEEP] ? "--add-keep" : "--del-keep");

      args = parseargs(argind, argc, argv);

      if (options[DEL_KEEP]) {
          switch (delkeep(kfile, args)) {
          case -1:
            error(EXIT_FAILURE, errno, "%s", kfile);
          case 1:
            error(EXIT_FAILURE, 0, "no packages removed.");
          }
      } else {
          i = pkggrep(sfile, args);
          if (i < 0)
            error(EXIT_FAILURE, errno, sfile);
          if (i)
            error(EXIT_FAILURE, 0, "%s: no such package.", args[i-1]);

          if ((i = hasduplicate(args)))
            error(EXIT_FAILURE, 0, "%s: duplicate entry.", args[i-1]);

          if (addkeep(kfile, args) < 0)
            error(EXIT_FAILURE, errno, "%s", kfile);
      }
      
      exit(EXIT_SUCCESS);
    }

    /* We don't want to merge the files if we're adding, because it's perfectly
       alright to have the same entry in debfoster and deborphan.
    */
#ifdef DEBFOSTER_KEEP
    if (!options[NO_DEBFOSTER]) {
      deb *dfkeep = readkeep(DEBFOSTER_KEEP);

      if (dfkeep) {
          dep *d = keep;
          keep = mergekeep(keep, dfkeep);
          free(d);
          free(dfkeep);
      }
    }
#endif

    search_for = parseargs(argind, argc, argv);

    if (!(sfile_content = debopen(sfile)))
      error(EXIT_FAILURE, errno, "%s", sfile);

#ifndef LOW_MEM
    sfile_content2 = sfile_content;
#endif

    this = package = (pkg_info *) xmalloc(sizeof(pkg_info));
    init_pkg(this);
    init_pkg_regex();

    while ((line = nextline(&sfile_content)) != NULL) {
      if ((!strchr("IPpSsEeDdRr", *line)) || (*line == ' '))
          continue;

      if (*line != '\0') {
          strstripchr(line, ' ');
          get_pkg_info(line, this);
      } else {
          if ( (this->self.name && exclude_list &&
                            bsearch(&this->self, exclude_list, exclude_list_cnt,
                                  sizeof(exclude_list[0]),
                                  (int(*)(const void*, const void*))depcmp) )
              || (!this->install && !options[FIND_CONFIG]) ) {
            reinit_pkg(this);
          } else {
            this->next = xmalloc(sizeof(pkg_info));
            this = this->next;
            init_pkg(this);
          }
      }
    }

#ifdef LOW_MEM
    free(line);
#else
    free(sfile_content2);
#endif

    this->next = NULL;
    this = package;

    /* Check the dependencies. Last package is handled specially, because it
       is not terminated with a \n in STATUS_FILE. */
    while (this->next) {
      check_lib_deps(package, this);
      this = this->next;
    }
    if (this->install)
      check_lib_deps(package, this);

    free_pkg_regex();

    fflush(stdout);

    for (i = 0; options[SEARCH] && search_for[i]; i++) {
      fprintf(stderr, "%s: package %s not found or not installed\n",
            argv[0], search_for[i]);
    }

    return i ? EXIT_FAILURE : EXIT_SUCCESS;
}

Generated by  Doxygen 1.6.0   Back to index