Logo Search packages:      
Sourcecode: debfoster version File versions  Download package

status.c

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>

#include "error.h"
#include "conffile.h"
#include "AVLTree.h"
#include "symbol.h"
#include "config.h"
#include "intl.h"
#include "status.h"

#define READBUF 4096

struct pinfo {
      char *name;
      char *section;
      char *predepends, *depends, *recommends, *suggests, *provides, *tasks;
      unsigned short installed:1;
      unsigned short keep:1;
      unsigned short nokeep:1;
};

/* Life is all about priorities */
static const char *debian_priorities[] = {
      "required",
      "important",
      "standard",
      "optional",
      "extra",
      "ANY",
      NULL
};

static AVLTree *priorities = NULL, *keepsections = NULL, *nokeepsections = NULL, *guessdepends = NULL;
AVLTree *packages;

int chomp(char *s) {
      int r;
      r = strlen(s)-1;
      if(r>=0 && s[r] == '\n') {
            s[r--] = '\0';
            if(r>=0 && s[r] == '\r')
                  s[r--] = '\0';
      }
      return r+2;
}

char *chop(char *s) {
      int r;
      r = chomp(s)-2;
      while(r>=0 && strchr(" \t\n\r", s[r]))
            s[r--] = '\0';
      while(*s && strchr(" \t\n\r", *s))
            s++;
      return s;
}

int pkgcmp(struct package *a, struct package *b) {
      return symcmp(a->name, b->name);
}

struct package *pkg_find(symbol_t s) {
      struct package p;
      AVLNode *n;
      p.name = s;
      n = AVLSearch(packages, &p);
      return n ? (struct package *)n->item : NULL;
}

void free_package(struct package *pkg) {
      AVLFreeNodes(&pkg->depends);
      AVLFreeNodes(&pkg->dependents);
      AVLFreeNodes(&pkg->provides);
      AVLFreeNodes(&pkg->providers);
      free(pkg);
}

struct package *new_package(symbol_t s) {
      struct package *pkg;

      pkg = xmalloc(sizeof(struct package));
      pkg->name = s;
      pkg->provider_count = 0;
      pkg->orphan_depends = 0;
      pkg->installed = 0;
      pkg->keep = 0;
      pkg->nokeep = 0;
      AVLInitTree(&pkg->depends, (AVLCompare)strcasecmp, NULL);
      AVLInitTree(&pkg->dependents, (AVLCompare)strcasecmp, NULL);
      AVLInitTree(&pkg->provides, (AVLCompare)strcasecmp, NULL);
      AVLInitTree(&pkg->providers, (AVLCompare)strcasecmp, NULL);
      return pkg;
}

struct package *get_package(symbol_t s)
{
      struct package *pkg = pkg_find(s);
      if(!pkg) {
            pkg = new_package(s);
            if (!AVLInsert(packages, pkg))
                  perror_exit(ERROR_SYSTEM, "AVLInsert()");
      }
      return pkg;
}

static void process_dep(AVLTree *t, char *s) {
      struct package *pkg, *ppkg;
      char *dep = s, *str = s;
      symbol_t name;
      int alternative_depend = 0;

      while(s && *s) {
              switch(*str) {
                  case ' ':
                  case '\t':
                        str++;
                        break;
                  case '(':
                        while (*str && *str++ != ')');
                        break;
                  case ',':
                        str++;
                  case '\0':
                        *dep++ = '\0';
                        if (*s) {
                              name = symbol(s);
                              AVLInsert(t, name);
                              ppkg = get_package(name);
                              if(alternative_depend) {
                                    while (s && (dep = strsep(&s, "|"))) {
                                          pkg = get_package(symbol(dep));
                                          AVLInsert(&pkg->provides, name);
                                    }
                              }
                              alternative_depend = 0;
                              s = dep = str;
                        }
                        break;
                  case '|':
                        alternative_depend = 1;
                  default:
                        *dep++ = *str++;
                        break;
            }
      }
}

static void process_package(struct pinfo *p) {
      static struct pinfo null = {0};
      struct package *pkg;

      if(p->name && p->installed) {
            symbol_t name = symbol(p->name);
            pkg = get_package(name);
            pkg->installed    = 1;
            pkg->keep   = p->keep;
            pkg->nokeep = p->nokeep;
            process_dep(&pkg->provides, p->provides);
            process_dep(&pkg->depends,  p->predepends);
            process_dep(&pkg->depends,  p->depends);
            process_dep(&pkg->depends,  p->recommends);
            process_dep(&pkg->depends,  p->suggests);
      }
      if(p->name)
            free(p->name);
      if(p->section)
            free(p->section);
      if(p->provides)
            free(p->provides);
      if(p->predepends)
            free(p->predepends);
      if(p->depends)
            free(p->depends);
      if(p->recommends)
            free(p->recommends);
      if(p->suggests)
            free(p->suggests);
      if(p->tasks)
            free(p->tasks);
      *p = null;
}

static void process_available(struct pinfo *p) {
      static struct pinfo null = {0};
      struct package *pkg;
      char *task_name;
      AVLTree tasks;
      AVLNode *c;

      if(p->name && p->tasks) {
            symbol_t name = symbol(p->name);
            pkg = pkg_find(name);
            if(pkg && pkg->installed) {
                  AVLInitTree(&tasks, (AVLCompare)strcasecmp, NULL);
                  process_dep(&tasks, p->tasks);
                  while((c = tasks.head) != NULL) {
                        task_name = xstrcat("task-", (char *)c->item);
                        pkg = get_package(symbol(task_name));
                        AVLInsert(&pkg->depends, name);
                        pkg->task = 1;
                        free(task_name);
                        AVLDeleteNode(&tasks, c);
                  }
            }
      }
      if(p->name)
            free(p->name);
      if(p->section)
            free(p->section);
      if(p->provides)
            free(p->provides);
      if(p->predepends)
            free(p->predepends);
      if(p->depends)
            free(p->depends);
      if(p->recommends)
            free(p->recommends);
      if(p->suggests)
            free(p->suggests);
      if(p->tasks)
            free(p->tasks);
      *p = null;
}

static void parse_status(char *s, struct pinfo *p) {
      char *word;

      do word = strsep(&s, " \t");
      while(word && !*word);
      if(UseHold)
            p->keep |= !strcasecmp(word, "hold");

      do word = strsep(&s, " \t");
      while(word && !*word);
      /* usually word is "ok" now */

      do word = strsep(&s, " \t");
      while(word && !*word);
      p->installed = !strcasecmp(word, "installed");
}

static int parse_line(char *s, struct pinfo *p) {
      switch(tolower(*s)) {
            case 'd':
                  if(!strncasecmp(s+1,"epends:",7))
                        p->depends = xstrdup(chop(s+8));
            break;
            case 'e':
                  if(UseEssential && !strncasecmp(s+1,"ssential:",9))
                        p->keep |= !strcasecmp(chop(s+10), "yes");
            break;
            case 'p':
                  switch(tolower(s[1])) {
                        case 'r':
                              switch(tolower(s[2])) {
                                    case 'e':
                                          if(UsePreDepends && !strncasecmp(s+3,"-depends:",9))
                                                p->predepends = xstrdup(chop(s+12));
                                    break;
                                    case 'i':
                                          if(!strncasecmp(s+3,"ority:",6))
                                                p->keep |= !!AVLSearch(priorities,chop(s+9));
                                    break;
                                    case 'o':
                                          if(!strncasecmp(s+3,"vides:",6))
                                                p->provides = xstrdup(chop(s+9));
                                    break;
                              }
                        break;
                        case 'a':
                              if(!strncasecmp(s+2,"ckage:",6))
                                    p->name = xstrdup(chop(s+8));
                        break;
                  }
            break;
            case 'r':
                  if(UseRecommends && !strncasecmp(s+1,"ecommends:",10))
                        p->recommends = xstrdup(chop(s+11));
            break;
            case 's':
                  switch(tolower(s[1])) {
                        case 'e':
                              if(!strncasecmp(s+2,"ction:",6)) {
                                    char *r = strrchr(s, '/');
                                    r = chop(r ? r+1 : s+8);
                                    p->keep |= !!AVLSearch(keepsections, r);
                                    p->nokeep |= !!AVLSearch(nokeepsections, r);
                              }
                        break;
                        case 'u':
                              if(UseSuggests && !strncasecmp(s+2,"ggests:",7))
                                    p->suggests = xstrdup(chop(s+9));
                        break;
                        case 't':
                              if(!strncasecmp(s+2,"atus:",5))
                                    parse_status(chop(s+7), p);
                        break;
                  }
            break;
            case 't':
                  if(!strncasecmp(s+1,"ask:",4))
                        p->tasks = xstrdup(chop(s+5));
            break;
            case ' ':
            case '\t':
            case '\r':
                  if(!*chop(s))
                        return 1;
                  break;
            case '\0':
            case '\n':
                  return 1;
      }
      return 0;
}

typedef void (*process_func)(struct pinfo *);
void readlines(const char *filename, process_func process_record) {
      struct pinfo p = {0};
      FILE *f;
      int fd;
      char *buf;
      char *s, *t;
      struct stat st;

      fd = open(filename, O_RDONLY);
      if(fd<0)
            perror_exit(ERROR_SYSTEM, DpkgStatus);

      if(!fstat(fd, &st)
      && S_ISREG(st.st_mode)
      && (buf = mmap(NULL,st.st_size,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0))) {
            if(buf[st.st_size-1] != '\n')
                  error_exit(ERROR_SYSTEM,
                        "%s is truncated (no trailing newline)\n", DpkgStatus);
            buf[st.st_size-1] = '\0';
            for(s = buf; s; s = t) {
                  t = strchr(s, '\n');
                  if(t)
                        *t++ = '\0';
                  if(parse_line(s, &p))
                        process_record(&p);
            }
            if(munmap(buf, st.st_size))
                  perror("munmap()");
            close(fd);
      } else {
            f = fdopen(fd, "r");
            if(!f)
                  perror_exit(ERROR_SYSTEM, DpkgStatus);
            buf = alloca(READBUF);
            if(!buf)
                  perror_exit(ERROR_SYSTEM, "alloca()");
            while(fgets(buf, READBUF, f))
                  if(parse_line(buf, &p))
                        process_record(&p);
            fclose(f);
      }
      process_record(&p);
}

AVLTree *initlist(AVLTree *tree, const char *str) {
      const char *s, *d = ", \t";
      int n;

      AVLInitTree(tree, (AVLCompare)strcasecmp, (AVLFreeItem)free);

      if (str) {
            for(s = str; *s; s += n + strspn(s, d)) {
                  n = strcspn(s, d);
                  AVLInsert(tree, xstrndup(s, n));
            }
      }

      return tree;
}

symbol_t guessbase(symbol_t name) {
      char *s;
      int n;

      if((s = strrchr(name, '-')) && AVLSearch(guessdepends, symbol(s+1))) {
            n = s - (char *)name;
            if (!(s = alloca(n+1)))
                  error_exit(ERROR_SYSTEM, "alloca()");
            strncpy(s, name, n);
            s[n] = '\0';
            return symbol(s);
      }

      return NULL;
}

void readstatus(void) {
      static AVLTree trees[4];
      const char **pri;

      AVLFreeNodes(packages);
      if(priorities)
            AVLFreeNodes(priorities);
      else
            priorities = AVLInitTree(trees, (AVLCompare)strcasecmp, NULL);
      if(!keepsections)
            keepsections = initlist(trees+1, KeepSections);
      if(!nokeepsections)
            nokeepsections = initlist(trees+2, NokeepSections);
      if(!guessdepends)
            guessdepends = initlist(trees+3, GuessDepends); 

      for(pri = debian_priorities; *pri && strcasecmp(MaxPriority, *pri); pri++)
            AVLInsert(priorities, (char *)*pri);
      if(!*pri)
            error_exit(ERROR_CONFIG, _("Unknown priority \"%s\"\n"), MaxPriority);

      readlines(DpkgStatus, process_package);         /* Read package status */
      if(UseTasks)
            readlines(DpkgAvailable, process_available);    /* Read additional info */
}

Generated by  Doxygen 1.6.0   Back to index