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