home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1999 May / pcp151c.iso / misc / src / install / pkgs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-28  |  30.5 KB  |  1,182 lines

  1. #include <alloca.h>
  2. #include <ctype.h>
  3. #include <dirent.h>
  4. #include <errno.h>
  5. #include <fcntl.h>
  6. #include <newt.h>
  7. #include <rpmlib.h>
  8. #include <header.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <sys/types.h>
  12. #include <unistd.h>
  13.  
  14. #include "hash.h"
  15. #include "install.h"
  16. #include "intl.h"
  17. #include "kickstart.h"
  18. #include "log.h"
  19. #include "pkgs.h"
  20. #include "windows.h"
  21.  
  22. #define FILENAME_TAG 1000000
  23.  
  24. static int selectPackagesByGroup(struct pkgSet * psp);
  25. static int selectPackagesWindow(struct pkgSet * psp, char * group,
  26.                 unsigned int * kSelected);
  27. static int skipPackage(char * name);
  28. static int selectComponents(struct componentSet * csp, struct pkgSet * psp,
  29.                 int * doIndividual);
  30. static int strptrCmp(const void * a, const void * b);
  31. static void showPackageInfo(Header h);
  32. static int queryIndividual(int * result);
  33.  
  34. char * skipList[] = { "XFree86-8514", "XFree86-AGX", "XFree86-Mach32",
  35.               "XFree86-Mach64", "XFree86-Mach8", "XFree86-Mono",
  36.               "XFree86-P9000", "XFree86-S3", "XFree86-S3V",
  37.               "XFree86-SVGA", "XFree86-VGA16", "XFree86-W32",
  38.               "XFree86-I128", "metroess", "metrotmpl", NULL };
  39.  
  40. static int strptrCmp(const void * a, const void * b) {
  41.     const char * const * one = a;
  42.     const char * const * two = b;
  43.  
  44.     return strcmp(*one, *two);
  45. }
  46.  
  47. int pkgCompare(void * first, void * second) {
  48.     struct packageInfo ** a = first;
  49.     struct packageInfo ** b = second;
  50.  
  51.     /* put packages w/o names at the end */
  52.     if (!(*a)->name) return 1;
  53.     if (!(*b)->name) return -1;
  54.  
  55.     return strcasecmp((*a)->name, (*b)->name);
  56. };
  57.  
  58. int psUsingDirectory(char * dirname, struct pkgSet * psp) {
  59.     DIR * dir;
  60.     struct dirent * ent;
  61.     int fd, rc, isSource;
  62.     Header h;
  63.     int packagesAlloced;
  64.     struct pkgSet ps;
  65.     int count, type;
  66.     unsigned int * sizeptr;
  67.     char * name, * group;
  68.     char * filename;
  69.  
  70.     ps.numPackages = 0;
  71.     packagesAlloced = 5;
  72.     ps.packages = malloc(sizeof(*ps.packages) * packagesAlloced);
  73.  
  74.     logMessage("scanning %s for packages", dirname);
  75.     dir = opendir(dirname);
  76.     if (!dir) {
  77.     errorWindow("error opening directory");
  78.     return INST_ERROR;
  79.     }
  80.  
  81.     errno = 0;
  82.     ent = readdir(dir);
  83.     if (errno) {
  84.     free(ps.packages);
  85.     errorWindow("error reading from directory");
  86.     closedir(dir);
  87.     return INST_ERROR;
  88.     }
  89.  
  90.     filename = alloca(strlen(dirname) + 500);
  91.  
  92.     winStatus(33, 3, "Running", "Scanning available packages...");
  93.  
  94.     while (ent) {
  95.     if (!(ent->d_name[0] == '.' && (ent->d_name[1] == '\0' || 
  96.         ((ent->d_name[1] == '.') && (ent->d_name[2] == '\0'))))) {
  97.         sprintf(filename, "%s/%s", dirname, ent->d_name);
  98.         fd = open(filename, O_RDONLY);
  99.  
  100.         if (fd < 0) {
  101.         logMessage("failed to open %s: %s", filename,
  102.                strerror(errno));
  103.         } else {
  104.         rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
  105.  
  106.         close(fd);
  107.         if (rc) {
  108.             logMessage("failed to rpmReadPackageHeader %s:", 
  109.                 ent->d_name);
  110.         } else {
  111.             if (ps.numPackages == packagesAlloced) {
  112.             packagesAlloced += 5;
  113.             ps.packages = realloc(ps.packages,
  114.                 sizeof(*ps.packages) * packagesAlloced);
  115.             }
  116.  
  117.             ps.packages[ps.numPackages] = 
  118.                 malloc(sizeof(struct packageInfo));
  119.             ps.packages[ps.numPackages]->h = h;
  120.             ps.packages[ps.numPackages]->selected = 0;
  121.             ps.packages[ps.numPackages]->data = strdup(ent->d_name);
  122.  
  123.             headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, 
  124.                     &count);
  125.             if (headerGetEntry(h, RPMTAG_SIZE, &type, (void **) 
  126.                   &sizeptr, &count))
  127.             ps.packages[ps.numPackages]->size = *sizeptr;
  128.             else
  129.             ps.packages[ps.numPackages]->size = 0;
  130.  
  131.             if (skipPackage(name)) 
  132.             ps.packages[ps.numPackages]->inmenu = 0;
  133.             else
  134.             ps.packages[ps.numPackages]->inmenu = 1;
  135.  
  136.             if (!headerGetEntry(h, RPMTAG_GROUP, &type, 
  137.                     (void **) &group, &count)) {
  138.             group = "(unknown group)";
  139.             } else if (!strlen(group)) {
  140.             group = "(unknown group)";
  141.             }
  142.  
  143.             ps.packages[ps.numPackages]->name = name;
  144.             ps.packages[ps.numPackages]->group = group;
  145.     
  146.             ps.numPackages++;
  147.         }
  148.         }
  149.     }
  150.  
  151.     errno = 0;
  152.     ent = readdir(dir);
  153.     if (errno) {
  154.         newtPopWindow();
  155.         errorWindow("error reading from directory (2): %s");
  156.         free(ps.packages);
  157.         closedir(dir);
  158.         return INST_ERROR;
  159.     }
  160.     } 
  161.  
  162.     *psp = ps;
  163.  
  164.     qsort(ps.packages, ps.numPackages, sizeof(*ps.packages), 
  165.       (void *) pkgCompare);
  166.     
  167.     closedir(dir);
  168.  
  169.     newtPopWindow();
  170.  
  171.     return 0;
  172. }
  173.  
  174. int psReadComponentsFile(char * filespec, struct pkgSet * psp, 
  175.              struct componentSet * csp) {
  176.     FILE * f;
  177.     char buf[255];
  178.     int inComp;
  179.     int line = 0;
  180.     char * start;
  181.     char * chptr;
  182.     int compsAlloced;
  183.     int packagesAlloced = 0;
  184.     struct componentSet cs;
  185.     struct component * currcomp = NULL;
  186.     struct packageInfo packkey, ** pack;
  187.     struct packageInfo * keyaddr = &packkey;
  188.     int i;
  189.     int baseNum = 0;
  190.  
  191.     f = fopen(filespec, "r");
  192.     if (!f) {
  193.     errorWindow(_("Cannot open components file: %s"));
  194.     return INST_ERROR;
  195.     }
  196.   
  197.     /* get the version number */
  198.     line++;
  199.     if (!fgets(buf, sizeof(buf), f)) {
  200.     errorWindow(_("Cannot read components file: %s"));
  201.     fclose(f);
  202.     return INST_ERROR;
  203.     }
  204.  
  205.     if (strcmp(buf, "0\n") && strcmp(buf, "0.1\n")) {
  206.     newtWinMessage(_("Error"), _("Ok"), 
  207.             _("Comps file is not version 0.1 as expected"));
  208.     fclose(f);
  209.     return INST_ERROR;
  210.     }
  211.  
  212.     compsAlloced = 5;
  213.     cs.numComponents = 0;
  214.     cs.comps = malloc(sizeof(*cs.comps) * compsAlloced);
  215.     cs.base = NULL;
  216.  
  217.     inComp = 0;
  218.     while (fgets(buf, sizeof(buf), f)) {
  219.     line++;
  220.  
  221.     /* remove any trailing '\n', leave chptr at the end of the string */
  222.     chptr = buf + strlen(buf) - 1;
  223.     if (*chptr == '\n') 
  224.         *chptr = '\0';
  225.     else
  226.         chptr++;
  227.  
  228.     /* strip leading spaces */
  229.     start = buf;
  230.     while (*start && isspace(*start)) start++;
  231.  
  232.     /* empty string */
  233.     if (!*start) continue;
  234.     
  235.     /* comment */
  236.     if (*start == '#') continue;
  237.  
  238.     if (!inComp) {
  239.         /* first digit must be a zero or a one */
  240.         if (*start != '0' && *start != '1') {
  241.         newtWinMessage(_("Error"), _("Ok"), 
  242.                 _("bad comps file at line %d"), line);
  243.         continue;
  244.         }
  245.  
  246.         if (compsAlloced == cs.numComponents) {
  247.         compsAlloced += 5;
  248.         cs.comps = realloc(cs.comps, sizeof(*cs.comps) * compsAlloced);
  249.         }
  250.  
  251.         currcomp = cs.comps + cs.numComponents;
  252.         currcomp->selected = (*start == '1');
  253.         currcomp->inmenu = 1;
  254.  
  255.         start++;
  256.         while (*start && isspace(*start)) start++;
  257.  
  258.         if (!strncmp(start, "--hide ", 7)) {
  259.         start += 7;
  260.         while (*start && isspace(*start)) start++;
  261.         currcomp->inmenu = 0;
  262.         }
  263.     
  264.  
  265.         if (!*start) {
  266.         newtWinMessage(_("comps Error"), _("Ok"),  
  267.                 _("missing component name at line %d"), line);
  268.         continue;
  269.         }
  270.  
  271.         currcomp->name = strdup(start);
  272.  
  273.         currcomp->ps.numPackages = 0;
  274.         packagesAlloced = 5;
  275.         currcomp->ps.packages = malloc(
  276.         sizeof(struct packageInfo) * packagesAlloced);
  277.         inComp = 1;
  278.     } else {
  279.         if (!strcmp(start, "end")) {
  280.         inComp = 0;
  281.  
  282.         if (!strcasecmp(currcomp->name, "Base"))
  283.             baseNum = cs.numComponents;
  284.  
  285.         cs.numComponents++;
  286.         } else {
  287.         packkey.name = start;
  288.         pack = bsearch(&keyaddr, psp->packages, psp->numPackages,
  289.                 sizeof(*psp->packages), (void *) pkgCompare);
  290.         if (!pack) {
  291.             newtWinMessage(_("comps Error"), _("Ok"), 
  292.                     _("package %s at line %d does not exist"), 
  293.                     start, line);
  294.             continue;
  295.         }
  296.  
  297.         if (currcomp->ps.numPackages == packagesAlloced) {
  298.             packagesAlloced += 5;
  299.             currcomp->ps.packages = realloc(currcomp->ps.packages,
  300.             sizeof(struct packageInfo) * packagesAlloced);
  301.         }
  302.  
  303.         currcomp->ps.packages[currcomp->ps.numPackages] = *pack;
  304.         currcomp->ps.numPackages++;
  305.         }
  306.     }
  307.     }
  308.  
  309.     fclose(f);
  310.  
  311.     cs.base = cs.comps + baseNum;
  312.  
  313.     cs.base->inmenu = 0;
  314.     cs.base->selected = 1;
  315.  
  316.     for (i = 0; i < cs.base->ps.numPackages; i++) {
  317.     cs.base->ps.packages[i]->inmenu = 0;
  318.     cs.base->ps.packages[i]->selected = 1;
  319.     }
  320.  
  321.     *csp = cs;
  322.  
  323.     return 0;
  324. }
  325.  
  326. struct packageCheckbox {
  327.     newtComponent cb, sizeLabel;
  328.     unsigned int * kSelected;
  329.     unsigned int size;
  330.     char state, lastState;
  331. };
  332.  
  333. static void sizeCallback(newtComponent co, struct packageCheckbox * cbi) {
  334.     char sizeBuf[20];
  335.  
  336.     if (cbi->state != cbi->lastState) {
  337.     if (cbi->state == ' ') 
  338.         *cbi->kSelected -= cbi->size / 1024;
  339.     else
  340.         *cbi->kSelected += cbi->size / 1024;
  341.     cbi->lastState = cbi->state;
  342.  
  343.     sprintf(sizeBuf, "%dM", *cbi->kSelected / 1024);
  344.     newtLabelSetText(cbi->sizeLabel, sizeBuf);
  345.     newtRefresh();
  346.     }
  347. }
  348.  
  349. static int selectPackagesWindow(struct pkgSet * psp, char * group,
  350.                 unsigned int * kSelected) {
  351.     newtComponent okay, form, checkList, sb, cancel, current, size, blank;
  352.     struct packageCheckbox * cbs;
  353.     int i, row, groupLength, rc;
  354.     char val;
  355.     struct newtExitStruct answer;
  356.     int done = 0;
  357.     char sizeBuf[20];
  358.     int exactMatch;
  359.     newtGrid grid, buttons, subgrid, checkgrid;
  360.  
  361.     if (!group) {
  362.     group = "";
  363.     groupLength = 0;
  364.     } else
  365.     groupLength = strlen(group);
  366.  
  367.     exactMatch = strchr(group, '/') ? 0 : 1;
  368.  
  369.     cbs = alloca(sizeof(*cbs) * psp->numPackages);
  370.  
  371.     newtPushHelpLine(
  372.     _("<F1> will show you a size and description of a package"));
  373.  
  374.     buttons = newtButtonBar(_("Ok"), &okay, _("Cancel"), &cancel, NULL);
  375.  
  376.     subgrid = newtCreateGrid(2, 1);
  377.     sprintf(sizeBuf, "%dM", *kSelected / 1024);
  378.     size = newtLabel(32, 10, sizeBuf);
  379.     newtGridSetField(subgrid, 0, 0, NEWT_GRID_COMPONENT,
  380.              newtLabel(-1, -1, _("Size of all selected packages:")),
  381.              0, 0, 0, 0, 0, 0);
  382.     newtGridSetField(subgrid, 1, 0, NEWT_GRID_COMPONENT, size,
  383.              1, 0, 0, 0, 0, 0);
  384.  
  385.     sb = newtVerticalScrollbar(29, 0, 6, 9, 10);
  386.     checkList = newtForm(sb, NULL, 0);
  387.     newtFormSetBackground(checkList, NEWT_COLORSET_CHECKBOX);
  388.  
  389.     for (i = 0, row = 0; i < psp->numPackages; i++) {
  390.     if (psp->packages[i]->inmenu &&
  391.         ((exactMatch && !strcmp(psp->packages[i]->group, group)) ||
  392.          (!exactMatch && strlen(psp->packages[i]->group) >= groupLength &&
  393.          !strncmp(psp->packages[i]->group, group, groupLength)))) {
  394.         if (psp->packages[i]->selected)
  395.         val = '*';
  396.         else
  397.         val = ' ';
  398.  
  399.         cbs[i].cb = newtCheckbox(1, row++, psp->packages[i]->name, val, 
  400.                      NULL, &cbs[i].state);
  401.         newtComponentAddCallback(cbs[i].cb, (void *) sizeCallback, cbs + i);
  402.         cbs[i].sizeLabel = size;
  403.         cbs[i].lastState = cbs[i].state = val;
  404.         cbs[i].size = psp->packages[i]->size;
  405.         cbs[i].kSelected = kSelected;
  406.         newtFormAddComponent(checkList, cbs[i].cb);
  407.     } else {
  408.         cbs[i].state = ' ';
  409.         cbs[i].cb = NULL;
  410.     }
  411.     }
  412.  
  413.     checkgrid = newtCreateGrid(3, 1);
  414.     newtGridSetField(checkgrid, 0, 0, NEWT_GRID_COMPONENT, checkList,
  415.          0, 0, 0, 0, 0, 0);
  416.     if (row > 6) {
  417.     blank = newtForm(NULL, NULL, 0);
  418.     newtFormSetWidth(blank, 2);
  419.     newtFormSetHeight(blank, 6);
  420.     newtFormSetBackground(blank, NEWT_COLORSET_CHECKBOX);
  421.     newtFormSetHeight(checkList, 6);
  422.     newtGridSetField(checkgrid, 1, 0, NEWT_GRID_COMPONENT, blank,
  423.              0, 0, 0, 0, 0, 0);
  424.     newtGridSetField(checkgrid, 2, 0, NEWT_GRID_COMPONENT, sb,
  425.              0, 0, 0, 0, 0, 0);
  426.     }
  427.  
  428.     grid = newtCreateGrid(1, 4);
  429.     newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT,
  430.              newtLabel(-1, -1, _("What packages should be installed?")),
  431.              0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  432.     newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, checkgrid,
  433.              0, 1, 0, 0, 0, 0);
  434.     newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, subgrid,
  435.              0, 1, 0, 0, NEWT_ANCHOR_LEFT, 0);
  436.     newtGridSetField(grid, 0, 3, NEWT_GRID_SUBGRID, buttons,
  437.              0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
  438.  
  439.     form = newtForm(NULL, NULL, 0);
  440.     newtGridAddComponentsToForm(grid, form, 1);
  441.     newtGridWrappedWindow(grid, _("Select Packages"));
  442.     newtGridFree(grid, 1);
  443.  
  444.     newtFormAddHotKey(form, NEWT_KEY_F1);
  445.  
  446.     rc = 0;
  447.     while (!done) {
  448.     newtFormRun(form, &answer);
  449.  
  450.     if (answer.reason == NEWT_EXIT_HOTKEY) {
  451.         if (answer.u.key == NEWT_KEY_F12) 
  452.         done = 1;
  453.         else if (answer.u.key == NEWT_KEY_F1) {
  454.         current = newtFormGetCurrent(checkList);
  455.         for (i = 0; i < psp->numPackages; i++) {
  456.             if (cbs[i].cb == current) {
  457.             showPackageInfo(psp->packages[i]->h);
  458.             break;
  459.             }
  460.         }
  461.         }
  462.     } else if (answer.reason == NEWT_EXIT_COMPONENT) {
  463.         done = 1;
  464.         if (answer.u.co == cancel)
  465.         rc = INST_CANCEL;
  466.     }
  467.     }
  468.  
  469.     newtFormDestroy(form);
  470.     newtPopWindow();
  471.     newtPopHelpLine();
  472.  
  473.     if (rc) return rc;
  474.  
  475.     for (i = 0; i < psp->numPackages; i++) 
  476.     if (cbs[i].cb)
  477.         if (cbs[i].state != ' ')
  478.            psp->packages[i]->selected = 1;
  479.         else
  480.            psp->packages[i]->selected = 0;
  481.  
  482.     return 0;
  483. }
  484.  
  485. #define SELECT_COMPONENTS    1
  486. #define SELECT_PACKAGES        2
  487. #define SELECT_VERIFY        3
  488. #define SELECT_DONE        100
  489.  
  490. int psSelectPackages(struct pkgSet * psp, struct componentSet * csp,
  491.              char * justComponent, int goForward, int isUpgrade) {
  492.     int rc;
  493.     int stage;
  494.     static int doIndividual = 0;
  495.     struct ksPackage * ksList;
  496.     int ksListLength;
  497.     int i, j, k;
  498.     struct packageInfo key;
  499.     struct packageInfo ** pack, * keyaddr = &key;
  500.  
  501.     if (justComponent) {
  502.     /* first off, turn on the base packages */
  503.     for (k = 0; k < csp->base->ps.numPackages; k++)
  504.         csp->base->ps.packages[k]->selected = 1;
  505.     csp->base->selected = 1;
  506.  
  507.     for (j = 0; j < csp->numComponents; j++)
  508.         if (!strcasecmp(justComponent, csp->comps[j].name))
  509.         break;
  510.  
  511.     if (j < csp->numComponents) {
  512.         for (k = 0; k < csp->comps[j].ps.numPackages; k++)
  513.         csp->comps[j].ps.packages[k]->selected = 1;
  514.         return 0;
  515.     }
  516.     }
  517.  
  518.     if (kickstart) {
  519.     ksGetPackageList(&ksList, &ksListLength);
  520.  
  521.     /* first off, turn on the base packages */
  522.     for (k = 0; k < csp->base->ps.numPackages; k++)
  523.         csp->base->ps.packages[k]->selected = 1;
  524.     csp->base->selected = 1;
  525.  
  526.     for (i = 0; i < ksListLength; i++) {
  527.         if (ksList[i].isComponent) {
  528.         for (j = 0; j < csp->numComponents; j++)
  529.             if (!strcasecmp(ksList[i].name, csp->comps[j].name))
  530.             break;
  531.         if (j == csp->numComponents) {
  532.             newtWinMessage(_("Kickstart Error"), _("Ok"), 
  533.                    _("Component %s does not exist.\n"),
  534.                    ksList[i].name);
  535.         } else {
  536.             for (k = 0; k < csp->comps[j].ps.numPackages; k++)
  537.             csp->comps[j].ps.packages[k]->selected = 1;
  538.         }
  539.         } else {
  540.         key.name = ksList[i].name;    
  541.         pack = bsearch(&keyaddr, psp->packages, psp->numPackages,
  542.                 sizeof(*psp->packages), (void *) pkgCompare);
  543.         if (!pack) {
  544.             newtWinMessage(_("Kickstart Error"), _("Ok"), 
  545.                    _("Package %s does not exist.\n"),
  546.                    key.name);
  547.         } else {
  548.             (*pack)->selected = 1;
  549.         }
  550.         }
  551.     }
  552.  
  553.     rc = psVerifyDependencies(psp, 1);
  554.  
  555.     return 0;
  556.     } else {
  557.     if (!goForward && doIndividual)
  558.         stage = SELECT_PACKAGES;
  559.     else
  560.         stage = SELECT_COMPONENTS;
  561.     }
  562.  
  563.     while (stage != SELECT_DONE) {
  564.     switch (stage) {
  565.       case SELECT_COMPONENTS:
  566.         if (isUpgrade)
  567.         rc = queryIndividual(&doIndividual);
  568.         else
  569.         rc = selectComponents(csp, psp, &doIndividual);
  570.         if (rc) return rc;
  571.         if (doIndividual)
  572.         stage = SELECT_PACKAGES;
  573.         else
  574.         stage = SELECT_VERIFY;
  575.         break;
  576.  
  577.       case SELECT_PACKAGES:
  578.         rc = selectPackagesByGroup(psp);
  579.         if (rc == INST_CANCEL) 
  580.         stage = SELECT_COMPONENTS;
  581.         else if (rc) 
  582.         return rc;
  583.         else
  584.         stage = SELECT_VERIFY;
  585.         break;
  586.  
  587.       case SELECT_VERIFY:
  588.         rc = psVerifyDependencies(psp, 0);
  589.         if (rc == INST_ERROR) 
  590.         return rc;
  591.         else if (rc)
  592.         stage = SELECT_PACKAGES;
  593.         else
  594.         stage = SELECT_DONE;
  595.     }
  596.     } 
  597.  
  598.     return 0;
  599. }
  600.  
  601. int psVerifyDependencies(struct pkgSet * psp, int fixup) {
  602.     rpmdb db = NULL;
  603.     rpmDependencies rpmdeps;
  604.     int i;
  605.     struct rpmDependencyConflict * conflicts;
  606.     struct packageInfo * package;
  607.     int numConflicts, numProblems;
  608.     newtComponent okay, form, textbox, info, cancel, answer;
  609.     newtGrid grid, buttons;
  610.     char * text, buf[80];
  611.     char selectPackages;
  612.     char * reflowedText;
  613.     int width, height;
  614.  
  615.     if (!access("/mnt/var/lib/rpm/packages.rpm", R_OK))
  616.     if (rpmdbOpen("/mnt", &db, O_RDWR | O_CREAT, 0644))
  617.         db = NULL;
  618.  
  619.     rpmdeps = rpmdepDependencies(db);
  620.  
  621.     for (i = 0; i < psp->numPackages; i++) {
  622.     if (psp->packages[i]->selected)
  623.         rpmdepAddPackage(rpmdeps, psp->packages[i]->h, psp->packages[i]);
  624.     else
  625.         rpmdepAvailablePackage(rpmdeps, psp->packages[i]->h, 
  626.                    psp->packages[i]);
  627.     }
  628.  
  629.     rpmdepCheck(rpmdeps, &conflicts, &numConflicts);
  630.  
  631.     rpmdepDone(rpmdeps);
  632.     if (db) rpmdbClose(db);
  633.  
  634.     /* XXX This is a hack. rpmlib seems to have problems in the conflicts 
  635.        stuff */
  636.     numProblems = 0;
  637.     for (i = 0; i < numConflicts; i++) {
  638.     if (conflicts[i].sense == RPMDEP_SENSE_REQUIRES) numProblems++;
  639.     }
  640.  
  641.     if (!numProblems) {
  642.     return 0;
  643.     }
  644.  
  645.     if (fixup) {
  646.     for (i = 0; i < numConflicts; i++) {
  647.         package = conflicts[i].suggestedPackage;
  648.         if (package) package->selected = 1;
  649.     }
  650.  
  651.     rpmdepFreeConflicts(conflicts, numConflicts);
  652.  
  653.     return 0;
  654.     }
  655.  
  656.     text = malloc(80 * numConflicts);
  657.     *text = '\0';
  658.     for (i = 0; i < numConflicts; i++) {
  659.     /* HACK XXX */
  660.     if (conflicts[i].sense == RPMDEP_SENSE_CONFLICTS) continue;
  661.  
  662.     package = conflicts[i].suggestedPackage;
  663.     if (package)
  664.         sprintf(buf, "%-20s %-20s", conflicts[i].byName, 
  665.             package->name);
  666.     else
  667.         sprintf(buf, "%-20s %s", conflicts[i].byName,
  668.             _("no suggestion"));
  669.  
  670.     if (i) strcat(text, "\n");
  671.     strcat(text, buf);
  672.     }
  673.  
  674.     if (!kickstart) {
  675.     form = newtForm(NULL, NULL, 0);
  676.  
  677.     reflowedText = newtReflowText(
  678.         _("Some of the packages you have selected to install require "
  679.           "packages you have not selected. If you just select Ok "
  680.           "all of those required packages will be installed."),
  681.           45, 5, 5, &width, &height);
  682.     info = newtTextbox(1, 1, width, height, NEWT_TEXTBOX_WRAP);
  683.     newtTextboxSetText(info, reflowedText);
  684.     free(reflowedText);
  685.  
  686.     sprintf(buf, "%-20s %-20s", _("Package"), _("Requirement"));
  687.     buttons = newtButtonBar(_("Ok"), &okay, _("Back"), &cancel, NULL);
  688.  
  689.     textbox = newtTextbox(-1, -1, 45, 5, 
  690.         numProblems > 5 ? NEWT_FLAG_SCROLL : 0);
  691.     newtTextboxSetText(textbox, text); 
  692.  
  693.     grid = newtCreateGrid(1, 5);
  694.  
  695.     newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, info,
  696.              0, 0, 0, 0, 0, 0);
  697.     newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, 
  698.              newtLabel(-1, -1, buf), 0, 1, 0, 0, 
  699.              NEWT_ANCHOR_LEFT, 0);
  700.     newtGridSetField(grid, 0, 2, NEWT_GRID_COMPONENT, textbox,
  701.              0, 0, 0, 0, 0, 0);
  702.     newtGridSetField(grid, 0, 3, NEWT_GRID_COMPONENT, 
  703.              newtCheckbox(-1, -1, _("Install packages to "
  704.                "satisfy dependencies"), '*', NULL, &selectPackages),
  705.              0, 1, 0, 0, 0, 0);
  706.     newtGridSetField(grid, 0, 4, NEWT_GRID_SUBGRID, buttons, 
  707.              0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
  708.  
  709.     newtGridAddComponentsToForm(grid, form, 1);
  710.     newtFormSetCurrent(form, okay);
  711.  
  712.     newtGridWrappedWindow(grid, _("Unresolved Dependencies"));
  713.     newtGridFree(grid, 1);
  714.     
  715.     answer = newtRunForm(form);
  716.  
  717.     newtFormDestroy(form);
  718.     newtPopWindow();
  719.  
  720.     if (answer == cancel) {
  721.         free(conflicts);
  722.         return INST_CANCEL;
  723.     }
  724.     }
  725.  
  726.     if (kickstart || selectPackages != ' ') {
  727.     for (i = 0; i < numConflicts; i++) {
  728.         package = conflicts[i].suggestedPackage;
  729.         if (package) package->selected = 1;
  730.     }
  731.     }
  732.  
  733.     free(conflicts);
  734.     
  735.     return 0;
  736. } ;
  737.  
  738. static int selectComponents(struct componentSet * csp, struct pkgSet * psp,
  739.                 int * doIndividual) {
  740.     int i, j;
  741.     newtComponent okay, form, checklist, checkbox, sb, cancel, answer, blank;
  742.     newtGrid buttons, checkgrid, grid;
  743.     char val, individualPackages, everything;
  744.     char * states;
  745.     int row;
  746.     int numCols, numRows;
  747.  
  748.     newtGetScreenSize(&numCols, &numRows);
  749.  
  750.     individualPackages = *doIndividual ? '*' : ' ';
  751.  
  752.     states = alloca(sizeof(*states) * csp->numComponents);
  753.  
  754.     form = newtForm(NULL, NULL, 0);
  755.  
  756.     sb = newtVerticalScrollbar(-1, -1, numRows - 18, 9, 10);
  757.     checklist = newtForm(sb, NULL, 0);
  758.     newtFormSetHeight(checklist, numRows - 18);
  759.     newtFormSetBackground(checklist, NEWT_COLORSET_CHECKBOX);
  760.  
  761.     for (i = 0, row = 0; i < csp->numComponents; i++) {
  762.     if (csp->comps[i].inmenu) {
  763.         if (csp->comps[i].selected)
  764.         val = '*';
  765.         else
  766.         val = ' ';
  767.  
  768.         checkbox = newtCheckbox(0, row++, csp->comps[i].name, val, 
  769.                     NULL, &states[i]);
  770.         newtFormAddComponent(checklist, checkbox);
  771.     } else 
  772.         states[i] = ' ';
  773.     }
  774.  
  775.     checkbox = newtCheckbox(0, row++, _("Everything"), ' ', 
  776.                 NULL, &everything);
  777.     newtFormAddComponent(checklist, checkbox);
  778.  
  779.     blank = newtForm(NULL, NULL, 0);
  780.     newtFormSetHeight(blank, numRows - 18);
  781.     newtFormSetWidth(blank, 2);
  782.     newtFormSetBackground(blank, NEWT_COLORSET_CHECKBOX);
  783.     checkgrid = newtGridHCloseStacked(NEWT_GRID_COMPONENT, checklist,
  784.                       NEWT_GRID_COMPONENT, blank,
  785.                       NEWT_GRID_COMPONENT, sb, NULL);
  786.  
  787.     checkbox = newtCheckbox(-1, -1, _("Select individual packages"), 
  788.                 individualPackages, NULL, &individualPackages);
  789.  
  790.     
  791.     buttons = newtButtonBar(_("Ok"), &okay, _("Back"), &cancel, NULL);
  792.  
  793.     grid = newtGridBasicWindow(newtLabel(-1, -1, 
  794.                     _("Choose components to install:")),
  795.                newtGridVStacked(NEWT_GRID_SUBGRID, checkgrid,
  796.                     NEWT_GRID_COMPONENT, checkbox, NULL),
  797.                buttons);
  798.  
  799.     newtGridAddComponentsToForm(grid, form, 1);
  800.     newtGridWrappedWindow(grid, _("Components to Install"));
  801.     newtGridFree(grid, 1);
  802.  
  803.     answer = newtRunForm(form);
  804.  
  805.     newtFormDestroy(form);
  806.     newtPopWindow();
  807.  
  808.     if (answer == cancel) return INST_CANCEL;
  809.  
  810.     *doIndividual = (individualPackages != ' ');
  811.  
  812.     if (everything != ' ') {
  813.     for (i = 0; i < psp->numPackages; i++) {
  814.         for (j = 0; skipList[j]; j++) {
  815.         if (!strcmp(psp->packages[i]->name, skipList[j])) break;
  816.         }
  817.         if (!skipList[j]) {
  818.         psp->packages[i]->selected = 1;
  819.         }
  820.     }
  821.     }
  822.  
  823.     for (i = 0; i < csp->numComponents; i++) {
  824.     if (csp->comps[i].inmenu) {
  825.         if (states[i] != ' ')
  826.         csp->comps[i].selected = 1;
  827.         else
  828.         csp->comps[i].selected = 0;
  829.  
  830.         for (j = 0; j < csp->comps[i].ps.numPackages; j++)
  831.         csp->comps[i].ps.packages[j]->selected |= 
  832.             csp->comps[i].selected;
  833.     }
  834.     }
  835.  
  836.     return 0;
  837. }
  838.  
  839. void psFreeComponentSet(struct componentSet * csp) {
  840.     int i;
  841.     struct component * currcomp;
  842.  
  843.     currcomp = csp->comps;
  844.     for (i = 0; i < csp->numComponents; i++, currcomp++) {
  845.     free(currcomp->ps.packages);
  846.     }
  847.  
  848.     free(csp->comps);
  849. }
  850.  
  851. int psFromHeaderListDesc(int fd, struct pkgSet * psp, int noSeek) {
  852.     struct pkgSet ps;
  853.     int end = 0, type, count;
  854.     unsigned int * sizeptr;
  855.     Header h;
  856.     int packagesAlloced;
  857.     char * name, * group;
  858.     int done = 0;
  859.  
  860.     ps.numPackages = 0;
  861.     packagesAlloced = 5;
  862.     ps.packages = malloc(sizeof(*ps.packages) * packagesAlloced);
  863.  
  864.     if (!noSeek) {
  865.     count = lseek(fd, 0, SEEK_CUR);
  866.     end = lseek(fd, 0, SEEK_END); 
  867.     lseek(fd, count, SEEK_SET); 
  868.     }
  869.  
  870.     while (!done) {
  871.     h = headerRead(fd, HEADER_MAGIC_YES);
  872.     if (!h && noSeek) {
  873.         done = 1;
  874.     } else if (!h) {
  875.         newtWinMessage(_("Error"), _("Ok"), "error reading header at %d\n", 
  876.             (int) lseek(fd, 0, SEEK_CUR));
  877.         free(ps.packages);
  878.         return INST_ERROR;
  879.     } else {
  880.         headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, &count);
  881.  
  882.         if (!headerGetEntry(h, RPMTAG_GROUP, &type, (void **) &group, 
  883.                 &count)) {
  884.         group = "(unknown group)";
  885.         } else if (!strlen(group))
  886.         group = "(unknown group)";
  887.  
  888.         if (ps.numPackages == packagesAlloced) {
  889.         packagesAlloced += 5;
  890.         ps.packages = realloc(ps.packages,
  891.             sizeof(*ps.packages) * packagesAlloced);
  892.         }
  893.  
  894.         ps.packages[ps.numPackages] = 
  895.             malloc(sizeof(struct packageInfo));
  896.         ps.packages[ps.numPackages]->h = h;
  897.         ps.packages[ps.numPackages]->selected = 0;
  898.  
  899.         if (headerGetEntry(h, RPMTAG_SIZE, &type, (void **) &sizeptr, 
  900.                 &count))
  901.         ps.packages[ps.numPackages]->size = *sizeptr;
  902.         else
  903.         ps.packages[ps.numPackages]->size = 0;
  904.  
  905.         if (skipPackage(name)) 
  906.         ps.packages[ps.numPackages]->inmenu = 0;
  907.         else
  908.         ps.packages[ps.numPackages]->inmenu = 1;
  909.  
  910.         ps.packages[ps.numPackages]->name = name;
  911.         ps.packages[ps.numPackages]->group = group;
  912.         headerGetEntry(h, FILENAME_TAG, &type,
  913.              (void **) &ps.packages[ps.numPackages]->data, 
  914.              &count);
  915.  
  916.         ps.numPackages++;
  917.     }
  918.  
  919.     if (!noSeek) {
  920.         if (end <= lseek(fd, 0, SEEK_CUR)) 
  921.         done = 1;
  922.     }
  923.     }
  924.  
  925.     logMessage("psFromHeaderListDesc read %d headers", ps.numPackages);
  926.  
  927.     *psp = ps;
  928.  
  929.     qsort(ps.packages, ps.numPackages, sizeof(*ps.packages), 
  930.       (void *) pkgCompare);
  931.     
  932.     return 0;
  933. }
  934.  
  935. int psFromHeaderListFile(char * file, struct pkgSet * psp) {
  936.     int fd, rc;
  937.  
  938.     fd = open(file, O_RDONLY, 0644);
  939.     if (fd < 0) {
  940.     errorWindow(_("error opening header file: %s"));
  941.     return INST_ERROR;
  942.     }
  943.  
  944.     rc = psFromHeaderListDesc(fd, psp, 0);
  945.     close(fd);
  946.  
  947.     return rc;
  948. }
  949.  
  950. static int skipPackage(char * name) {
  951.     char ** item;
  952.  
  953.     for (item = skipList; *item; item++) {
  954.     if (!strcmp(*item, name)) return 1;
  955.     }
  956.  
  957.     return 0;
  958. }
  959.  
  960. static int selectPackagesByGroup(struct pkgSet * psp) {
  961.     newtComponent done, edit, form, listbox, back, answer;
  962.     newtComponent sizeLabel;
  963.     int i, row, numGroups;
  964.     unsigned int kSelected = 0;
  965.     int rc = 0;
  966.     hashTable ht;
  967.     htIterator iter;
  968.     char buf[200], * chptr;
  969.     char * group;
  970.     char ** groupList;
  971.     newtGrid grid, subgrid, sizegrid, buttons;
  972.  
  973.     ht = htNewTable(psp->numPackages);
  974.     for (i = 0, row = 0; i < psp->numPackages; i++) {
  975.     if (psp->packages[i]->inmenu) {
  976.         group = psp->packages[i]->group;
  977.         chptr = group;
  978.         while (*chptr && *chptr != '/') chptr++;
  979.         if (*chptr == '/') {
  980.         chptr++;
  981.         while (*chptr && *chptr != '/') chptr++;
  982.         if (*chptr == '/') {
  983.             strncpy(buf, group, chptr - group);
  984.             buf[chptr - group] = '\0';
  985.             group = buf;
  986.         }
  987.         }
  988.     }
  989.  
  990.     htAddToTable(ht, group);
  991.  
  992.     if (psp->packages[i]->selected)
  993.         kSelected += (psp->packages[i]->size / 1024);
  994.     }
  995.  
  996.     numGroups = htNumEntries(ht);
  997.     groupList = alloca(sizeof(*groupList) * numGroups);
  998.     htIterStart(&iter);
  999.     i = 0;
  1000.     while (htIterGetNext(ht, &iter, &group)) {
  1001.     groupList[i] = alloca(strlen(group) + 1);
  1002.     strcpy(groupList[i], group);
  1003.     i++;
  1004.     }
  1005.  
  1006.     qsort(groupList, numGroups, sizeof(char *), strptrCmp);
  1007.     htFreeHashTable(ht);
  1008.  
  1009.     form = newtForm(NULL, NULL, 0);
  1010.  
  1011.     buttons = newtButtonBar(_("Done"), &done, _("Edit"), &edit, 
  1012.                 _("Back"), &back, NULL);
  1013.  
  1014.     sprintf(buf, "%dM", kSelected / 1024);
  1015.     while (strlen(buf) < 5)
  1016.     strcat(buf, " ");
  1017.     sizeLabel = newtLabel(-1, -1, buf);
  1018.  
  1019.     /* FIXME: this windo isn't quite right -- looks like some newt bugs */
  1020.  
  1021.     sizegrid = newtCreateGrid(2, 1);
  1022.     newtGridSetField(sizegrid, 0, 0, NEWT_GRID_COMPONENT,
  1023.              newtLabel(-1, -1, _("Size:")),
  1024.              0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  1025.     newtGridSetField(sizegrid, 1, 0, NEWT_GRID_COMPONENT, sizeLabel,
  1026.              1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  1027.  
  1028.  
  1029.     subgrid = newtCreateGrid(2, 1);
  1030.     newtGridSetField(subgrid, 0, 0, NEWT_GRID_COMPONENT,
  1031.              newtLabel(-1, -1, _("Choose a group to examine:")),
  1032.              0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  1033.     newtGridSetField(subgrid, 1, 0, NEWT_GRID_SUBGRID, sizegrid,
  1034.              5, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  1035.  
  1036.     listbox = newtListbox(3, 3, 6, NEWT_FLAG_RETURNEXIT | NEWT_FLAG_SCROLL);
  1037.  
  1038.     for (i = 0; i < numGroups; i++) 
  1039.     newtListboxAddEntry(listbox, groupList[i], groupList[i]);
  1040.  
  1041.     grid = newtCreateGrid(1, 3);
  1042.     newtGridSetField(grid, 0, 0, NEWT_GRID_SUBGRID, subgrid,
  1043.              0, 0, 0, 0, 0, 0);
  1044.     newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, listbox,
  1045.              0, 1, 0, 0, 0, 0);
  1046.     newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
  1047.              0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
  1048.  
  1049.     newtGridAddComponentsToForm(grid, form, 1);
  1050.     newtGridWrappedWindowAt(grid, _("Select Group"), 1, 2);
  1051.     newtGridFree(grid, 1);
  1052.  
  1053.     do {
  1054.     answer = newtRunForm(form);
  1055.     if ((answer == listbox) || (answer == edit)) {
  1056.         group = newtListboxGetCurrent(listbox);
  1057.         rc = selectPackagesWindow(psp, group, &kSelected);
  1058.  
  1059.         sprintf(buf, "%dM", kSelected / 1024);
  1060.         newtLabelSetText(sizeLabel, buf);
  1061.     }
  1062.     } while (((answer == listbox) || (answer == edit)) && rc != INST_ERROR);
  1063.  
  1064.     newtFormDestroy(form);
  1065.     newtPopWindow();
  1066.  
  1067.     if (rc == INST_ERROR) return rc;
  1068.  
  1069.     if (answer == back) return INST_CANCEL;
  1070.  
  1071.     return 0;
  1072. }
  1073.  
  1074. static void showPackageInfo(Header h) {
  1075.     newtComponent form, textbox, okay;
  1076.     newtGrid subgrid, grid;
  1077.     char * name, * version, * description, * release;
  1078.     uint_32 * size;
  1079.     int type, count;
  1080.     char infostr[255];
  1081.     char * buf, * from, * to;
  1082.  
  1083.     headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, &count);
  1084.     headerGetEntry(h, RPMTAG_VERSION, &type, (void **) &version, &count);
  1085.     headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) &release, &count);
  1086.  
  1087.     if (!headerGetEntry(h, RPMTAG_SIZE, &type, (void **) &size, &count))
  1088.     size = 0;
  1089.  
  1090.     if (!headerGetEntry(h, RPMTAG_DESCRIPTION, &type, (void **) &description, 
  1091.         &count)) {
  1092.     if (!headerGetEntry(h, RPMTAG_SUMMARY, &type, (void **) &description, 
  1093.         &count)) {
  1094.         description = _("(none available)");
  1095.     }
  1096.     }
  1097.  
  1098.     subgrid = newtCreateGrid(2, 2);
  1099.  
  1100.     newtGridSetField(subgrid, 0, 0, NEWT_GRID_COMPONENT,
  1101.              newtLabel(-1, 1, _("Package:")),
  1102.              0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  1103.     newtGridSetField(subgrid, 0, 1, NEWT_GRID_COMPONENT,
  1104.              newtLabel(-1, -1, _("Size   :")),
  1105.              0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  1106.  
  1107.     sprintf(infostr, "%s-%s-%s", name, version, release);
  1108.     newtGridSetField(subgrid, 1, 0, NEWT_GRID_COMPONENT,
  1109.              newtLabel(-1, -1, infostr),
  1110.              1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  1111.  
  1112.     sprintf(infostr, "%d", *size);
  1113.     newtGridSetField(subgrid, 1, 1, NEWT_GRID_COMPONENT,
  1114.              newtLabel(-1, -1, infostr),
  1115.              1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  1116.  
  1117.  
  1118.     to = buf = alloca(strlen(description) + 1);
  1119.     from = description; 
  1120.     /* Rip out all '\n' that don't start new paragraphs */
  1121.     while (*from) {
  1122.     if (*from == '\n') {
  1123.         if ((*(from + 1) && isspace(*(from + 1))) ||
  1124.         (from > description && *(from - 1) == '\n'))
  1125.         *to++ = '\n';
  1126.         else
  1127.         *to++ = ' ';
  1128.     } else
  1129.         *to++ = *from;
  1130.     from++;
  1131.     }
  1132.     *to = '\0';
  1133.  
  1134.     textbox = newtTextbox(-1, -1, 43, 6, NEWT_TEXTBOX_WRAP | 
  1135.                 NEWT_TEXTBOX_SCROLL);
  1136.     newtTextboxSetText(textbox, buf);
  1137.  
  1138.     okay = newtButton(20, 11, _("Ok"));
  1139.  
  1140.     grid = newtCreateGrid(1, 3);
  1141.     newtGridSetField(grid, 0, 0, NEWT_GRID_SUBGRID, subgrid,
  1142.              0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  1143.     newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, textbox,
  1144.              0, 1, 0, 0, NEWT_ANCHOR_LEFT, 0);
  1145.     newtGridSetField(grid, 0, 2, NEWT_GRID_COMPONENT, okay, 
  1146.              0, 1, 0, 0, 0, 0);
  1147.  
  1148.     form = newtForm(NULL, NULL, 0);
  1149.     newtGridAddComponentsToForm(grid, form, 1);
  1150.     newtGridWrappedWindowAt(grid, name, 31, 6);
  1151.     newtGridFree(grid, 1);
  1152.  
  1153.     newtRunForm(form);
  1154.  
  1155.     newtFormDestroy(form);
  1156.     newtPopWindow();
  1157. }
  1158.  
  1159. static int queryIndividual(int * result) {
  1160.     int rc = 0;
  1161.  
  1162.     *result = 0;
  1163.  
  1164.     rc = newtWinTernary(_("Upgrade Packages"), _("Yes"), _("No"), _("Back"),
  1165.     _("The packages you have installed, and any other packages which are "
  1166.       "needed to satisfy their dependencies, have been selected for "
  1167.       "installation. Would you like to customize the set of packages that "
  1168.       "will be upgraded?"));
  1169.  
  1170.     if (rc == 3)
  1171.     rc = INST_CANCEL;
  1172.     else if (rc == 2) {
  1173.     *result = 0;
  1174.     rc = 0;
  1175.     } else {
  1176.     *result = 1;
  1177.     rc = 0;
  1178.     }
  1179.  
  1180.     return rc;
  1181. }
  1182.