#include #include #include #include #include #include #include /* for mkdir(2) ?!? */ #include #include #include #include #include #include "kickstart.h" #include "config.h" #include "doit.h" #include "install.h" #include "kbd.h" #include "log.h" #include "windows.h" extern int testing; FILE * logFile = NULL; static int installPackage(rpmdb db, struct installMethod * method, struct packageInfo * pkg, int isPreskel, int errfd, char * netSharedPath, int flags); static void setupXfree(struct installMethod * method, rpmdb db, struct pkgSet * psp, char * netSharedPath, int errfd); static void setupXmetro(struct installMethod * method, rpmdb db, struct packageInfo * pkg, struct packageInfo * tmplPkg, char * netSharedPath, int errfd); static void setupX(struct installMethod * method, rpmdb db, struct pkgSet * psp, char * netSharedPath, int errfd); static void rpmerror(void); static void swOpen(int numPackages, int sizePackages); static void swPackage(Header h); static void swPackageComplete(); static void swClose(void); static void swCallback(const unsigned long amount, const unsigned long total); static void formatTime(char * buf, time_t t); int doInstall(struct installMethod * method, struct pkgSet * psp, char * netSharedPath, char * keymap, int upgrade) { int i, totalNumPackages, totalSizePackages; struct packageInfo ** orderedPackages; int flags = 0; rpmdb db; int errfd; char * logFileName = "/dev/tty5"; rpmDependencies rpmdeps, rpmorder; char * hostEntry = "127.0.0.1 localhost localhost.localdomain\n"; int fd; if (testing) return 0; mkdir("/mnt/etc", 0755); mkdir("/mnt/tmp", 0755); mkdir("/mnt/var", 0755); mkdir("/mnt/var/tmp", 0755); mkdir("/mnt/var/lib", 0755); mkdir("/mnt/var/lib/rpm", 0755); if (!upgrade) { fd = open("/mnt/etc/hosts", O_CREAT | O_RDWR, 0644); if (fd < 0) { errorWindow("Failed to create /mnt/etc/hosts: %s."); return INST_ERROR; } write(fd, hostEntry, strlen(hostEntry)); close(fd); } if (upgrade) { flags |= RPMINSTALL_UPGRADE | RPMINSTALL_REPLACEFILES; logFile = fopen("/mnt/tmp/upgrade.log", "w"); } else logFile = fopen("/mnt/tmp/install.log", "w"); if (logFile) { setlinebuf(logFile); if (upgrade) { logMessage("opened /mnt/tmp/upgrade.log"); } else { logMessage("opened /mnt/tmp/install.log"); } } else { if (upgrade) { logMessage("failed to open /mnt/tmp/upgrade.log :-("); errorWindow("Failed to open /mnt/tmp/upgrade.log. No upgrade log " "will be kept."); } else { logMessage("failed to open /mnt/tmp/install.log :-("); errorWindow("Failed to open /mnt/tmp/install.log. No install log " "will be kept."); } } errfd = open(logFileName, O_APPEND | O_CREAT, 0644); if (errfd < 0) { logMessage("failed to open /dev/tty5!"); logFileName = "/tmp/exec.log"; errfd = open(logFileName, O_APPEND | O_CREAT, 0644); if (errfd < 0) { logMessage("failed to open %s: %s!\n", logFileName, strerror(errno)); errfd = 2; } } rpmErrorSetCallback(rpmerror); logMessage("reading /usr/lib/rpmrc"); rpmReadConfigFiles(NULL, NULL, NULL, 0); logMessage("\tdone"); if (rpmdbOpen("/mnt", &db, O_RDWR | O_CREAT, 0644)) { errorWindow("Fatal error opening RPM database"); return INST_ERROR; } logMessage("opened rpm database"); rpmdeps = rpmdepDependencies(db); rpmorder = rpmdepDependencies(NULL); for (i = 0; i < psp->numPackages; i++) { if (!strcmp(psp->packages[i]->name, "basesystem")) { rpmdepAddPackage(rpmdeps, psp->packages[i]->h, psp->packages[i]); rpmdepAddPackage(rpmorder, psp->packages[i]->h, psp->packages[i]); } } totalNumPackages = 0, totalSizePackages = 0; for (i = 0; i < psp->numPackages; i++) { if (psp->packages[i]->selected) { if (strcmp(psp->packages[i]->name, "basesystem")) { rpmdepAddPackage(rpmdeps, psp->packages[i]->h, psp->packages[i]); rpmdepAddPackage(rpmorder, psp->packages[i]->h, psp->packages[i]); } totalSizePackages += psp->packages[i]->size; totalNumPackages++; } } if (rpmdepOrder(rpmorder, (void ***) &orderedPackages)) { rpmdbClose(db); newtWinMessage("Error", "Ok", "Error ordering package list: %s", rpmErrorString()); close(errfd); return 1; } rpmdepDone(rpmdeps); rpmdepDone(rpmorder); if (testing) { newtWinMessage("Status", "Ok", "Packages would be installed now"); return 0; } swOpen(totalNumPackages, totalSizePackages); logMessage("installing %d packages", totalNumPackages); for (i = 0; i < totalNumPackages; i++) { installPackage(db, method, orderedPackages[i], 0, errfd, netSharedPath, flags); } swClose(); free(orderedPackages); #ifndef __sparc__ if (!upgrade) { mkdir("/mnt/etc/sysconfig", 0755); writeKbdConfig("/mnt/etc/sysconfig", keymap); } #endif if (!upgrade) { mouseConfig(); setupX(method, db, psp, netSharedPath, errfd); } rpmdbClose(db); close(errfd); if (logFile) fclose(logFile); logMessage("rpm database closed"); return 0; } static int installPackage(rpmdb db, struct installMethod * method, struct packageInfo * pkg, int isPreskel, int errfd, char * netSharedPath, int flags) { int fd, olderr; char * realName; int olderrno, rc; if (flags & RPMINSTALL_UPGRADE) { if (logFile) fprintf(logFile, "Upgrading %s.\n", pkg->name); } else { if (logFile) fprintf(logFile, "Installing %s.\n", pkg->name); } swPackage(pkg->h); if (method->getFile(method, pkg->data, &realName, isPreskel)) { logMessage("getFile method failed for %s", pkg->data); if (logFile) fprintf(logFile, "Failed to get file for package %s.\n", pkg->name); swPackageComplete(); return 1; } fd = open(realName, O_RDONLY); if (fd < 0) { olderrno = errno; logMessage("cannot open RPM file %s: %s", pkg->data, strerror(olderrno)); newtWinMessage("Error", "Ok", "Error installing package: cannot open RPM file " "for %s: %s", pkg->data, strerror(errno)); if (logFile) fprintf(logFile, "\tcannot open RPM file %s: %s\n", (char *) pkg->data, strerror(olderrno)); swPackageComplete(); return 1; } /* this is a hack */ if (!strcmp(pkg->name, "kernel-modules")) flags |= RPMINSTALL_NOSCRIPTS; olderr = dup(2); dup2(errfd, 2); rc = rpmInstallPackage("/mnt", db, fd, NULL, flags | RPMINSTALL_REPLACEPKG | RPMINSTALL_REPLACEFILES, swCallback, NULL, netSharedPath); dup2(olderr, 2); close(olderr); if (rc) { olderrno = errno; logMessage("Error installing package: package install of " "%s failed: %s", pkg->name, rpmErrorString()); newtWinMessage("Error", "Ok", "RPM install of %s failed: %s", pkg->name, rpmErrorString()); if (logFile) fprintf(logFile, "\tcannot open RPM file %s: %s\n", (char *) pkg->data, strerror(olderrno)); } close(fd); swPackageComplete(); if (method->rmFiles) unlink(realName); return 0; } static void setupX(struct installMethod * method, rpmdb db, struct pkgSet * psp, char * netSharedPath, int errfd) { int hasMetro = 0, i; newtComponent text, yes, no, form, answer; struct packageInfo * metroPackage = NULL; struct packageInfo * metroTmplPackage = NULL; /* This is a cheap trick to see if our X component was installed */ if (access("/mnt/usr/X11R6/bin/Xconfigurator", X_OK)) { logMessage("/mnt/usr/X11R6/bin/Xconfigurator cannot be run"); return; } logMessage("looking for metrox"); for (i = 0; i < psp->numPackages; i++) { if (!strcmp(psp->packages[i]->name, "metroess")) { logMessage("\tfound metrolink!"); metroPackage = psp->packages[i]; hasMetro = 1; } else if (!strcmp(psp->packages[i]->name, "metrotmpl")) { logMessage("\tfound metrotmpl!"); metroTmplPackage = psp->packages[i]; } } if (!hasMetro || kickstart) return setupXfree(method, db, psp, netSharedPath, errfd); newtCenteredWindow(60, 16, "Metro-X"); text = newtTextbox(1, 1, 58, 9, NEWT_TEXTBOX_WRAP); newtTextboxSetText(text, "This copy of Red Hat Linux includes MetroX from MetroLink.\n\n" "MetroX is LICENSED SOFTWARE. Your purchase of Red Hat Linux " "entitles you to one (1) user license for this software. You " "may not install and run MetroX on more than one computer " "without purchasing additional licenses, which are available " "from Red Hat Software (800) 454-5502. Would you like to install " "MetroX on your computer?"); yes = newtButton(13, 12, "Yes"); no = newtButton(36, 12, "No"); form = newtForm(NULL, NULL, 0); newtFormAddComponents(form, text, yes, no, NULL); newtRunForm(form); answer = newtFormGetCurrent(form); newtFormDestroy(form); newtPopWindow(); if (answer == yes) { setupXmetro(method, db, metroPackage, metroTmplPackage, netSharedPath, errfd); } else { setupXfree(method, db, psp, netSharedPath, errfd); } } static void setupXmetro(struct installMethod * method, rpmdb db, struct packageInfo * pkg, struct packageInfo * tmplPkg, char * netSharedPath, int errfd) { int childpid; int status; swOpen(tmplPkg ? 2 : 1, pkg->size + (tmplPkg ? tmplPkg->size : 0)); installPackage(db, method, pkg, 0, errfd, netSharedPath, 0); if (tmplPkg) installPackage(db, method, tmplPkg, 0, errfd, netSharedPath, 0); swClose(); symlink("../../usr/X11R6/bin/Xmetro", "/mnt/etc/X11/X"); newtSuspend(); if (!(childpid = fork())) { chroot("/mnt"); putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/X11R6/bin"); chdir("/"); execl("/usr/bin/metrotmpl", "/usr/bin/metrotmpl", NULL); } waitpid(childpid, &status, 0); if (!(childpid = fork())) { chroot("/mnt"); putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/X11R6/bin"); chdir("/"); close(2); execl("/usr/X11R6/bin/configX", "/usr/X11R6/bin/configX", NULL); } waitpid(childpid, &status, 0); newtResume(); } static void setupXfree(struct installMethod * method, rpmdb db, struct pkgSet * psp, char * netSharedPath, int errfd) { int fd, i; char buf[200], * chptr; char server[50]; int rc; /* need proc to do pci probing */ if ((rc = doMount("/proc", "/mnt/proc", "proc", 0, 0))) { return; } /* this handles kickstart and normal/expert modes */ if ((rc=xfree86Config("--pick"))) return; if ((fd = open("/mnt/tmp/SERVER", O_RDONLY)) < 0) { logMessage("failed to open /mnt/tmp/SERVER: %s", strerror(errno)); return; } buf[0] = '\0'; read(fd, buf, sizeof(buf)); close(fd); chptr = buf; while (chptr < (buf + sizeof(buf) - 1) && *chptr && *chptr != ' ') chptr++; if (chptr >= (buf + sizeof(buf) - 1) || *chptr != ' ') { logMessage("couldn't find ' ' in /mnt/tmp/SERVER"); return; } *chptr = '\0'; strcpy(server, "XFree86-"); strcat(server, buf); logMessage("I will install the %s package", server); for (i = 0; i < psp->numPackages; i++) { if (!strcmp(psp->packages[i]->name, server)) { logMessage("\tfound package: %s", psp->packages[i]->name); swOpen(1, psp->packages[i]->size); installPackage(db, method, psp->packages[i], 0, errfd, netSharedPath, 0); swClose(); break; } } /* this handles kickstart and normal/expert modes */ if ((rc=xfree86Config("--continue"))) return; /* done with proc now */ umount("/mnt/proc"); } static void rpmerror(void) { int code; code = rpmErrorCode(); if (code != RPMERR_UNLINK && code != RPMERR_RMDIR) { if (logFile) fprintf(logFile, "%s\n", rpmErrorString()); else logMessage(rpmErrorString()); } } static struct statusWindowInfo { newtComponent form, packageLabel, sizeLabel, summaryText; newtComponent pkgScale, globalScale; newtComponent pkgDoneLabel, pkgRemainsLabel; newtComponent sizeDoneLabel, sizeRemainsLabel; newtComponent timeDoneLabel, timeRemainsLabel, timeTotalLabel; int numPackages, packagesDone; unsigned int sizePackages, sizeDone; int thisPackageSize; time_t timeStarted; } si; static void swOpen(int numPackages, int sizePackages) { char buf[50]; newtCenteredWindow(60, 15, "Install Status"); si.form = newtForm(NULL, NULL, 0); newtFormAddComponent(si.form, newtLabel(1, 1, "Package:")); newtFormAddComponent(si.form, newtLabel(1, 2, "Size :")); newtFormAddComponent(si.form, newtLabel(1, 3, "Summary:")); si.packageLabel = newtLabel(13, 1, ""); si.sizeLabel = newtLabel(13, 2, ""); si.summaryText = newtTextbox(13, 3, 45, 2, NEWT_TEXTBOX_WRAP); si.pkgScale = newtScale(3, 6, 54, 100); newtFormAddComponent(si.form, newtLabel(1, 8, " Packages Bytes Time")); /* 12345678901234567890123456789012345678901234567 1 2 3 4 */ newtFormAddComponent(si.form, newtLabel(1, 9, "Total :")); newtFormAddComponent(si.form, newtLabel(1, 10, "Completed :")); newtFormAddComponent(si.form, newtLabel(1, 11, "Remaining :")); si.numPackages = numPackages; si.sizePackages = sizePackages; si.packagesDone = 0; si.sizeDone = 0; si.timeStarted = time(NULL); sprintf(buf, "%8d", numPackages); newtFormAddComponent(si.form, newtLabel(14, 9, buf)); si.pkgDoneLabel = newtLabel(14, 10, ""); si.pkgRemainsLabel = newtLabel(14, 11, ""); sprintf(buf, "%4uM", sizePackages / (1024 * 1024)); newtFormAddComponent(si.form, newtLabel(29, 9, buf)); si.sizeDoneLabel = newtLabel(29, 10, ""); si.sizeRemainsLabel = newtLabel(29, 11, ""); si.timeTotalLabel = newtLabel(42, 9, ""); si.timeDoneLabel = newtLabel(42, 10, ""); si.timeRemainsLabel = newtLabel(42, 11, ""); si.globalScale = newtScale(1, 13, 58, sizePackages); newtFormAddComponents(si.form, si.packageLabel, si.sizeLabel, si.summaryText, si.pkgScale, si.globalScale, si.pkgDoneLabel, si.pkgRemainsLabel, si.sizeDoneLabel, si.sizeRemainsLabel, si.timeDoneLabel, si.timeRemainsLabel, si.timeTotalLabel, NULL); } static void swPackage(Header h) { char * name, * version, * release, * summary; char buf[50]; uint_32 * size; headerGetEntry(h, RPMTAG_NAME, NULL, (void *) &name, NULL); headerGetEntry(h, RPMTAG_VERSION, NULL, (void *) &version, NULL); headerGetEntry(h, RPMTAG_RELEASE, NULL, (void *) &release, NULL); headerGetEntry(h, RPMTAG_SIZE, NULL, (void *) &size, NULL); if (!headerGetEntry(h, RPMTAG_SUMMARY, NULL, (void *) &summary, NULL)) summary = "(no summary)"; sprintf(buf, "%s-%s-%s", name, version, release); newtLabelSetText(si.packageLabel, buf); sprintf(buf, "%dk", (*size) / 1024); newtLabelSetText(si.sizeLabel, buf); newtTextboxSetText(si.summaryText, summary); si.thisPackageSize = *size; newtScaleSet(si.pkgScale, 0); newtDrawForm(si.form); newtRefresh(); } static void swPackageComplete(void) { char buf[50]; time_t now, finishTime, elapsedTime, remainingTime; si.packagesDone++; si.sizeDone += si.thisPackageSize; sprintf(buf, "%8d", si.packagesDone); newtLabelSetText(si.pkgDoneLabel, buf); sprintf(buf, "%8d", si.numPackages - si.packagesDone); newtLabelSetText(si.pkgRemainsLabel, buf); sprintf(buf, "%4dM", si.sizeDone / (1024 * 1024)); newtLabelSetText(si.sizeDoneLabel, buf); sprintf(buf, "%4dM", (si.sizePackages - si.sizeDone) / (1024 * 1024)); newtLabelSetText(si.sizeRemainsLabel, buf); now = time(NULL); elapsedTime = now - si.timeStarted; formatTime(buf, elapsedTime); newtLabelSetText(si.timeDoneLabel, buf); finishTime = (((float) si.sizePackages) / si.sizeDone) * elapsedTime; formatTime(buf, finishTime); newtLabelSetText(si.timeTotalLabel, buf); remainingTime = finishTime - elapsedTime; formatTime(buf, remainingTime); newtLabelSetText(si.timeRemainsLabel, buf); newtScaleSet(si.globalScale, si.sizeDone); newtRefresh(); } static void swCallback(const unsigned long amount, const unsigned long total) { if (total == 0) newtScaleSet(si.pkgScale, 100); else newtScaleSet(si.pkgScale, (amount * 100) / total); newtRefresh(); } static void swClose(void) { newtPopWindow(); } static void formatTime(char * buf, time_t t) { int hours, minutes, secs; hours = t / 60 / 60; t %= (60 * 60); minutes = t / 60; t %= 60; secs = t; sprintf(buf, "%01d:%02d.%02d", hours, minutes, secs); }