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