home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 13 / CDA13.ISO / MISC / SRC / INSTALL / DOIT.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-23  |  15.9 KB  |  582 lines

  1. #include <errno.h>
  2. #include <fcntl.h>
  3. #include <newt.h>
  4. #include <rpmlib.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <sys/stat.h>        /* for mkdir(2) ?!? */
  8. #include <sys/time.h>
  9. #include <sys/wait.h>
  10. #include <unistd.h>
  11.  
  12. #include "config.h"
  13. #include "doit.h"
  14. #include "install.h"
  15. #include "log.h"
  16. #include "windows.h"
  17.  
  18. extern int testing;
  19. FILE * logFile = NULL;
  20.  
  21. static int installPackage(rpmdb db, struct installMethod * method, 
  22.               struct packageInfo * pkg, int isPreskel, 
  23.               int errfd, char * netSharedPath, int flags);
  24. static void setupXfree(struct installMethod * method, rpmdb db, 
  25.                struct pkgSet * psp, char * netSharedPath, int errfd);
  26. static void setupXmetro(struct installMethod * method, rpmdb db, 
  27.                 struct packageInfo * pkg, char * netSharedPath,
  28.             int errfd);
  29. static void setupX(struct installMethod * method, rpmdb db, 
  30.            struct pkgSet * psp, char * netSharedPath, int errfd);
  31. static void rpmerror(void);
  32.  
  33. static void swOpen(int numPackages, int sizePackages);
  34. static void swPackage(Header h);
  35. static void swPackageComplete();
  36. static void swClose(void);
  37. static void swCallback(const unsigned long amount, const unsigned long total);
  38. static void formatTime(char * buf, time_t t);
  39.  
  40. static int installCpioArchive(struct installMethod * method, char * name,
  41.                   char * logFileName) {
  42.     char * realName;
  43.     char cmd[500];
  44.     int olderrno;
  45.     int rc;
  46.     
  47.     if (method->getFile(method, name, &realName, 1)) {
  48.     if (logFile)
  49.         fprintf(logFile, "Failed to get cpio archive %s.\n", name);
  50.     return INST_ERROR;
  51.     }
  52.  
  53.     chdir("/mnt");
  54.     sprintf(cmd, "gunzip < %s | cpio -iumd --quiet 2>%s >%s", 
  55.         realName, logFileName, logFileName);
  56.  
  57.     logMessage("running: \"%s\"", cmd);
  58.  
  59.     if (testing) {
  60.     messageWindow("would run: %s", cmd);
  61.     return 0;
  62.     }
  63.  
  64.     rc = system(cmd);
  65.  
  66.     if (method->rmFiles) unlink(realName);
  67.  
  68.     if (rc) {
  69.     olderrno = errno;
  70.     logMessage("    command failed: %s rc = %d\n", strerror(olderrno), rc);
  71.     olderrno = errno;
  72.     errorWindow("error unpacking archive: %s");
  73.     return INST_ERROR;
  74.     }
  75.  
  76.     return 0;
  77. }
  78.  
  79. int doInstall(struct installMethod * method, struct component * preskel, 
  80.           struct pkgSet * psp, char * netSharedPath, int upgrade) {
  81.     int i, totalNumPackages, totalSizePackages;
  82.     int flags = 0;
  83.     rpmdb db;
  84.     int errfd;
  85.     char * logFileName = "/dev/tty5";
  86.  
  87.     mkdir("/mnt/tmp", 0755);
  88.     mkdir("/mnt/var", 0755);
  89.     mkdir("/mnt/var/lib", 0755);
  90.     mkdir("/mnt/var/lib/rpm", 0755);
  91.  
  92.     if (upgrade) {
  93.     flags |= RPMINSTALL_UPGRADE | RPMINSTALL_REPLACEFILES;
  94.     logFile = fopen("/mnt/tmp/upgrade.log", "w");
  95.     } else
  96.     logFile = fopen("/mnt/tmp/install.log", "w");
  97.     if (logFile) {
  98.     if (upgrade) {
  99.         logMessage("opened /mnt/tmp/upgrade.log");
  100.     } else {
  101.         logMessage("opened /mnt/tmp/install.log");
  102.     }
  103.     } else {
  104.     if (upgrade) {
  105.         logMessage("failed to open /mnt/tmp/upgrade.log :-(");
  106.         errorWindow("Failed to open /mnt/tmp/upgrade.log. No upgrade log "
  107.                 "will be kept.");
  108.     } else {
  109.         logMessage("failed to open /mnt/tmp/install.log :-(");
  110.         errorWindow("Failed to open /mnt/tmp/install.log. No install log "
  111.                 "will be kept.");
  112.     }
  113.     }
  114.  
  115.     errfd = open(logFileName, O_APPEND | O_CREAT, 0644);
  116.     if (errfd < 0) {
  117.     logMessage("failed to open /dev/tty5!");
  118.     logFileName = "/tmp/exec.log";
  119.     errfd = open(logFileName, O_APPEND | O_CREAT, 0644);
  120.     if (errfd < 0) {
  121.         logMessage("failed to open %s: %s!\n", logFileName, 
  122.             strerror(errno));
  123.         errfd = 2;
  124.     }
  125.     }
  126.  
  127.     rpmErrorSetCallback(rpmerror);
  128.  
  129.     logMessage("reading /usr/lib/rpmrc");
  130.     rpmReadConfigFiles(NULL, NULL, NULL, 0);
  131.     logMessage("\tdone");
  132.  
  133.     if (testing) {
  134.     messageWindow("Status", "Packages would be installed now");
  135.     return 0;
  136.     }
  137.  
  138.     if (rpmdbOpen("/mnt", &db, O_RDWR | O_CREAT, 0644)) {
  139.     errorWindow("Fatal error opening RPM database");
  140.     return INST_ERROR;
  141.     }
  142.     logMessage("opened rpm database");
  143.  
  144.     /* It's safer to *always* install the base system */
  145.     winStatus(45, 3, "Base system", "Installing base system...");
  146.  
  147.     if (installCpioArchive(method, "skeleton.cgz", logFileName))
  148.     return INST_ERROR;
  149.  
  150.     newtPopWindow();
  151.  
  152.     logMessage("installing initial packages (%d of them)", 
  153.         preskel->ps.numPackages);
  154.  
  155.     totalNumPackages = 0, totalSizePackages = 0;
  156.     for (i = 0; i < psp->numPackages; i++) {
  157.     if (psp->packages[i]->selected) {
  158.         totalSizePackages += psp->packages[i]->size;
  159.         totalNumPackages++;
  160.     }
  161.     }
  162.  
  163.     swOpen(totalNumPackages, totalSizePackages);
  164.  
  165.     for (i = 0; i < preskel->ps.numPackages; i++) {
  166.     if (!preskel->ps.packages[i]->selected) continue;
  167.     logMessage("    installing %s", preskel->ps.packages[i]->name);
  168.     installPackage(db, method, preskel->ps.packages[i], 1, errfd, 
  169.             netSharedPath, flags);
  170.     preskel->ps.packages[i]->selected = 0;    /* don't install it later */
  171.     }
  172.  
  173.     logMessage("installing packages");
  174.     for (i = 0; i < psp->numPackages; i++) {
  175.     if (!psp->packages[i]->selected) continue;
  176.     installPackage(db, method, psp->packages[i], 0, errfd, 
  177.             netSharedPath, flags);
  178.     }
  179.     swClose();
  180.  
  181.     if (!upgrade) {
  182.     kbdConfig();
  183.     mouseConfig();
  184.         setupX(method, db, psp, netSharedPath, errfd);
  185.     }
  186.  
  187.     rpmdbClose(db);
  188.     close(errfd);
  189.  
  190.     if (logFile) fclose(logFile);
  191.  
  192.     logMessage("rpm database closed");
  193.  
  194.     return 0;
  195. }
  196.  
  197. static int installPackage(rpmdb db, struct installMethod * method, 
  198.               struct packageInfo * pkg, int isPreskel, 
  199.               int errfd, char * netSharedPath, int flags) {
  200.     int fd, olderr;
  201.     char * realName;
  202.     int olderrno, rc;
  203.  
  204.     if (flags & RPMINSTALL_UPGRADE) {
  205.     if (logFile)
  206.         fprintf(logFile, "Upgrading %s.\n", pkg->name);
  207.     } else {
  208.     if (logFile)
  209.         fprintf(logFile, "Installing %s.\n", pkg->name);
  210.     }
  211.  
  212.     swPackage(pkg->h);
  213.  
  214.     if (method->getFile(method, pkg->data, &realName, isPreskel)) {
  215.     logMessage("getFile method failed for %s", pkg->data);
  216.     if (logFile)
  217.         fprintf(logFile, "Failed to get file for package %s.\n", pkg->name);
  218.     swPackageComplete();
  219.     return 1;
  220.     }
  221.  
  222.     fd = open(realName, O_RDONLY);
  223.     if (fd < 0) {
  224.     olderrno = errno;
  225.     logMessage("cannot open RPM file %s: %s", pkg->data,
  226.             strerror(olderrno));
  227.     messageWindow("Error", "Error installing package: cannot open RPM file "
  228.             "for %s: %s", pkg->data, strerror(errno));
  229.     if (logFile)
  230.         fprintf(logFile, "\tcannot open RPM file %s: %s\n", 
  231.             (char *) pkg->data, strerror(olderrno));
  232.  
  233.     swPackageComplete();
  234.  
  235.     return 1;
  236.     }
  237.  
  238.     olderr = dup(2);
  239.     dup2(errfd, 2);
  240.     rc = rpmInstallPackage("/mnt", db, fd, NULL, 
  241.         flags | RPMINSTALL_REPLACEPKG | RPMINSTALL_REPLACEFILES, 
  242.             swCallback, NULL, netSharedPath);
  243.     dup2(olderr, 2);
  244.     close(olderr);
  245.  
  246.     if (rc) {
  247.     olderrno = errno;
  248.     logMessage("Error installing package: package install of %s failed", 
  249.             pkg->name);
  250.     messageWindow("Error", "RPM install of %s failed", pkg->name);
  251.     if (logFile)
  252.         fprintf(logFile, "\tcannot open RPM file %s: %s\n", 
  253.             (char *) pkg->data, strerror(olderrno));
  254.     } 
  255.  
  256.     close(fd);
  257.     swPackageComplete();
  258.  
  259.     if (method->rmFiles) unlink(realName);
  260.  
  261.     return 0;
  262. }
  263.  
  264. static void setupX(struct installMethod * method, rpmdb db, 
  265.            struct pkgSet * psp, char * netSharedPath, int errfd) {
  266.     int hasMetro = 0, i;
  267.     newtComponent text, yes, no, form, answer;
  268.     struct packageInfo * metroPackage = NULL;
  269.  
  270.     /* This is a cheap trick to see if our X component was installed */
  271.     if (access("/mnt/usr/X11R6/bin/Xconfigurator", X_OK)) {
  272.     logMessage("/mnt/usr/X11R6/bin/Xconfigurator cannot be run");
  273.     return;
  274.     }
  275.  
  276.     logMessage("looking for metrox");
  277.     for (i = 0; i < psp->numPackages; i++) {
  278.     if (!strcmp(psp->packages[i]->name, "metroess")) {
  279.         logMessage("\tfound metrolink!");
  280.         metroPackage = psp->packages[i];
  281.         hasMetro = 1;
  282.         break;
  283.     }
  284.     }
  285.  
  286.     if (!hasMetro)
  287.     return setupXfree(method, db, psp, netSharedPath, errfd);
  288.  
  289.     newtOpenWindow(10, 4, 60, 16, "Metro-X");
  290.  
  291.     text = newtTextbox(1, 1, 58, 9, NEWT_TEXTBOX_WRAP);
  292.     newtTextboxSetText(text, 
  293.     "This copy of Red Hat Linux includes MetroX from MetroLink.\n\n" 
  294.     "MetroX is LICENSED SOFTWARE.  Your purchase of Red Hat Linux "
  295.     "entitles you to one (1) user license for this software.  You "
  296.     "may not install and run MetroX on more than one computer "
  297.     "without purchasing additional licenses, which are available "
  298.     "from Red Hat Software (800) 454-5502. Would you like to install "
  299.     "MetroX on your computer?");
  300.     yes = newtButton(13, 12, "Yes");
  301.     no = newtButton(36, 12, "No");
  302.     
  303.     form = newtForm(NULL, NULL, 0);
  304.     newtFormAddComponents(form, text, yes, no, NULL);
  305.  
  306.     newtRunForm(form);
  307.     answer = newtFormGetCurrent(form);
  308.  
  309.     newtFormDestroy(form);
  310.     newtPopWindow();
  311.  
  312.     if (answer == yes) {
  313.     setupXmetro(method, db, metroPackage, netSharedPath, errfd);
  314.     } else {
  315.     setupXfree(method, db, psp, netSharedPath, errfd);
  316.     }
  317. }
  318.  
  319. static void setupXmetro(struct installMethod * method, rpmdb db, 
  320.                 struct packageInfo * pkg, char * netSharedPath,
  321.             int errfd) {
  322.     int childpid;
  323.     int status;
  324.  
  325.     swOpen(1, pkg->size);
  326.     installPackage(db, method, pkg, 0, errfd, netSharedPath, 0);
  327.     swClose();
  328.  
  329.     symlink("../../usr/X11R6/bin/Xmetro", "/mnt/etc/X11/X");
  330.  
  331.     newtSuspend();
  332.     if (!(childpid = fork())) {
  333.     chroot("/mnt");
  334.     putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/X11R6/bin");
  335.     chdir("/");
  336.     execl("/usr/X11R6/bin/configX", "/usr/X11R6/bin/configX", NULL);
  337.     }
  338.  
  339.     waitpid(childpid, &status, 0);
  340.  
  341.     newtResume();
  342. }
  343.  
  344. static void setupXfree(struct installMethod * method, rpmdb db, 
  345.                struct pkgSet * psp, char * netSharedPath, int errfd) {
  346.     int childpid;
  347.     int status;
  348.     int fd, i;
  349.     char buf[200], * chptr;
  350.     char server[50];
  351.  
  352.     newtSuspend();
  353.     if (!(childpid = fork())) {
  354.     chroot("/mnt");
  355.     putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/X11R6/bin");
  356.     chdir("/");
  357.     execl("/usr/X11R6/bin/Xconfigurator", "/usr/X11R6/bin/Xconfigurator",
  358.           "--pick", NULL);
  359.     }
  360.  
  361.     waitpid(childpid, &status, 0);
  362.  
  363.     newtResume();
  364.  
  365.     if ((fd = open("/mnt/tmp/SERVER", O_RDONLY)) < 0) {
  366.     logMessage("failed to open /mnt/tmp/SERVER: %s", strerror(errno));
  367.     return;
  368.     }
  369.  
  370.     buf[0] = '\0';
  371.     read(fd, buf, sizeof(buf));
  372.     close(fd);
  373.     chptr = buf;
  374.     while (chptr < (buf + sizeof(buf) - 1) && *chptr && *chptr != ' ')
  375.     chptr++;
  376.  
  377.     if (chptr >= (buf + sizeof(buf) - 1) || *chptr != ' ') {
  378.     logMessage("couldn't find ' ' in /mnt/tmp/SERVER");
  379.     return;
  380.     }
  381.  
  382.     *chptr = '\0';
  383.     strcpy(server, "XFree86-");
  384.     strcat(server, buf);
  385.  
  386.     logMessage("I will install the %s package", server);
  387.  
  388.     for (i = 0; i < psp->numPackages; i++) {
  389.     if (!strcmp(psp->packages[i]->name, server)) {
  390.         logMessage("\tfound package: %s", psp->packages[i]->name);
  391.         swOpen(1, psp->packages[i]->size);
  392.         installPackage(db, method, psp->packages[i], 0, errfd, 
  393.                 netSharedPath, 0);
  394.         swClose();
  395.         break;
  396.     }
  397.     }
  398.  
  399.     newtSuspend();
  400.     if (!(childpid = fork())) {
  401.     chroot("/mnt");
  402.     chdir("/");
  403.     execl("/usr/X11R6/bin/Xconfigurator", "/usr/X11R6/bin/Xconfigurator",
  404.           "--continue", NULL);
  405.     }
  406.  
  407.     waitpid(childpid, &status, 0);
  408.  
  409.     newtResume();
  410. }
  411.  
  412. static void rpmerror(void) {
  413.     int code;
  414.  
  415.     code = rpmErrorCode();
  416.     if (code != RPMERR_UNLINK && code != RPMERR_RMDIR) {
  417.     if (logFile)
  418.         fprintf(logFile, "%s\n", rpmErrorString());
  419.     else
  420.         logMessage(rpmErrorString());
  421.     }
  422. }
  423.  
  424. static struct statusWindowInfo {
  425.     newtComponent form, packageLabel, sizeLabel, summaryText;
  426.     newtComponent pkgScale, globalScale;
  427.     newtComponent pkgDoneLabel, pkgRemainsLabel;
  428.     newtComponent sizeDoneLabel, sizeRemainsLabel;
  429.     newtComponent timeDoneLabel, timeRemainsLabel, timeTotalLabel;
  430.     int numPackages, packagesDone;
  431.     unsigned int sizePackages, sizeDone;
  432.     int thisPackageSize;
  433.     time_t timeStarted;
  434. } si;
  435.  
  436. static void swOpen(int numPackages, int sizePackages) {
  437.     char buf[50];
  438.  
  439.     newtOpenWindow(10, 4, 60, 15, "Install Status");
  440.  
  441.     si.form = newtForm(NULL, NULL, 0);
  442.     newtFormAddComponent(si.form, newtLabel(1, 1, "Package:"));
  443.     newtFormAddComponent(si.form, newtLabel(1, 2, "Size   :"));
  444.     newtFormAddComponent(si.form, newtLabel(1, 3, "Summary:"));
  445.  
  446.     si.packageLabel = newtLabel(13, 1, "");
  447.     si.sizeLabel    = newtLabel(13, 2, "");
  448.     si.summaryText  = newtTextbox(13, 3, 45, 2, NEWT_TEXTBOX_WRAP);
  449.  
  450.     si.pkgScale = newtScale(3, 6, 54, 100);
  451.  
  452.     newtFormAddComponent(si.form, 
  453.     newtLabel(1, 8, "             Packages       Bytes           Time"));
  454.     /*         12345678901234567890123456789012345678901234567
  455.                   1         2         3         4 */
  456.     newtFormAddComponent(si.form, newtLabel(1, 9,  "Total     :"));
  457.     newtFormAddComponent(si.form, newtLabel(1, 10, "Completed :"));
  458.     newtFormAddComponent(si.form, newtLabel(1, 11, "Remaining :"));
  459.  
  460.     si.numPackages = numPackages;
  461.     si.sizePackages = sizePackages;
  462.     si.packagesDone = 0;
  463.     si.sizeDone = 0;
  464.     si.timeStarted = time(NULL);
  465.  
  466.     sprintf(buf, "%8d", numPackages);
  467.     newtFormAddComponent(si.form, newtLabel(14, 9, buf));
  468.     si.pkgDoneLabel = newtLabel(14, 10, "");
  469.     si.pkgRemainsLabel = newtLabel(14, 11, "");
  470.  
  471.     sprintf(buf, "%4uM", sizePackages / (1024 * 1024));
  472.     newtFormAddComponent(si.form, newtLabel(29, 9, buf));
  473.     si.sizeDoneLabel = newtLabel(29, 10, "");
  474.     si.sizeRemainsLabel = newtLabel(29, 11, "");
  475.  
  476.     si.timeTotalLabel = newtLabel(42, 9, "");
  477.     si.timeDoneLabel = newtLabel(42, 10, "");
  478.     si.timeRemainsLabel = newtLabel(42, 11, "");
  479.  
  480.     si.globalScale = newtScale(1, 13, 58, sizePackages);
  481.  
  482.     newtFormAddComponents(si.form, si.packageLabel, si.sizeLabel, 
  483.               si.summaryText, si.pkgScale, si.globalScale, 
  484.               si.pkgDoneLabel, si.pkgRemainsLabel, 
  485.               si.sizeDoneLabel, si.sizeRemainsLabel, 
  486.               si.timeDoneLabel, si.timeRemainsLabel,
  487.               si.timeTotalLabel, NULL);
  488. }
  489.  
  490. static void swPackage(Header h) {
  491.     char * name, * version, * release, * summary;
  492.     char buf[50];
  493.     uint_32 * size;
  494.  
  495.     headerGetEntry(h, RPMTAG_NAME, NULL, (void *) &name, NULL);
  496.     headerGetEntry(h, RPMTAG_VERSION, NULL, (void *) &version, NULL);
  497.     headerGetEntry(h, RPMTAG_RELEASE, NULL, (void *) &release, NULL);
  498.     headerGetEntry(h, RPMTAG_SIZE, NULL, (void *) &size, NULL);
  499.  
  500.     if (!headerGetEntry(h, RPMTAG_SUMMARY, NULL, (void *) &summary, NULL))
  501.     summary = "(no summary)";
  502.  
  503.     sprintf(buf, "%s-%s-%s", name, version, release);
  504.     newtLabelSetText(si.packageLabel, buf);
  505.  
  506.     sprintf(buf, "%dk", (*size) / 1024);
  507.     newtLabelSetText(si.sizeLabel, buf);
  508.  
  509.     newtTextboxSetText(si.summaryText, summary);
  510.  
  511.     si.thisPackageSize = *size;
  512.  
  513.     newtScaleSet(si.pkgScale, 0);
  514.  
  515.     newtDrawForm(si.form);
  516.     newtRefresh();
  517. }
  518.  
  519. static void swPackageComplete(void) {
  520.     char buf[50];
  521.     time_t now, finishTime, elapsedTime, remainingTime;
  522.  
  523.     si.packagesDone++;
  524.     si.sizeDone += si.thisPackageSize;
  525.  
  526.     sprintf(buf, "%8d", si.packagesDone);
  527.     newtLabelSetText(si.pkgDoneLabel, buf);
  528.  
  529.     sprintf(buf, "%8d", si.numPackages - si.packagesDone);
  530.     newtLabelSetText(si.pkgRemainsLabel, buf);
  531.  
  532.     sprintf(buf, "%4dM", si.sizeDone / (1024 * 1024));
  533.     newtLabelSetText(si.sizeDoneLabel, buf);
  534.  
  535.     sprintf(buf, "%4dM", (si.sizePackages - si.sizeDone) / (1024 * 1024));
  536.     newtLabelSetText(si.sizeRemainsLabel, buf);
  537.  
  538.     now = time(NULL);
  539.     elapsedTime = now - si.timeStarted;
  540.     formatTime(buf, elapsedTime);
  541.     newtLabelSetText(si.timeDoneLabel, buf);
  542.  
  543.     finishTime = (((float) si.sizePackages) / si.sizeDone) * elapsedTime;
  544.     formatTime(buf, finishTime);
  545.     newtLabelSetText(si.timeTotalLabel, buf);
  546.     
  547.     remainingTime = finishTime - elapsedTime;
  548.     formatTime(buf, remainingTime);
  549.     newtLabelSetText(si.timeRemainsLabel, buf);
  550.  
  551.     newtScaleSet(si.globalScale, si.sizeDone);
  552.  
  553.     newtRefresh();
  554. }
  555.  
  556. static void swCallback(const unsigned long amount, const unsigned long total) {
  557.     if (total == 0)
  558.     newtScaleSet(si.pkgScale, 100);
  559.     else
  560.     newtScaleSet(si.pkgScale, (amount * 100) / total);
  561.  
  562.     newtRefresh();
  563. }
  564.  
  565. static void swClose(void) {
  566.     newtPopWindow();
  567. }
  568.  
  569. static void formatTime(char * buf, time_t t) {
  570.     int hours, minutes, secs;
  571.  
  572.     hours = t / 60 / 60;
  573.     t %= (60 * 60);
  574.  
  575.     minutes = t / 60;
  576.     t %= 60;
  577.  
  578.     secs = t;
  579.  
  580.     sprintf(buf, "%01d:%02d.%02d", hours, minutes, secs);
  581. }
  582.