#include #include #include #include #include #include #include /* for mkdir(2) ?!? */ #include #include #include #include #include #include #include "setup.h" #include "doit.h" #include "install.h" #include "intl.h" #include "kbd.h" #include "kickstart.h" #include "log.h" #include "syslog.h" #include "windows.h" #define FILESIZE_TAG 1000001 extern int testing; extern int_32 archiveSize; extern pid_t syncPid; extern pid_t syslogPid; FILE * logFile = NULL; 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 Header h, const rpmCallbackType what, const unsigned long amount, const unsigned long total, const void * pkgKey, void * data); static void formatTime(char * buf, time_t t); static int probSort(const void * one, const void * two); struct callbackInfo { struct packageInfo * pkg; int upgrade; struct installMethod * method; FD_t fd; char *lastFile; int archiveSize; int step; newtComponent statusForm, statusScale; int totalnum, totalsize; }; 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; int doInstall(struct installMethod * method, char * rootPath, struct pkgSet * psp, char * netSharedPath, char * keymap, char * kbdtype, int upgrade) { int i, totalNumPackages, totalSizePackages; rpmdb db; FD_t lfFd; char * path; rpmTransactionSet trans; rpmProblemSet probs; char * hostEntry = "127.0.0.1 localhost localhost.localdomain\n"; int fd; struct callbackInfo cbi; char *procPath; if (testing) return 0; path = alloca(strlen(rootPath) + 20); fd = open(".", O_RDONLY); chdir(rootPath); mkdir("dev", 0755); mkdir("etc", 0755); mkdir("tmp", 0755); mkdir("var", 0755); mkdir("var/tmp", 0755); mkdir("var/lib", 0755); mkdir("var/lib/rpm", 0755); mkdir("proc", 0755); fchdir(fd); close(fd); #ifdef __sparc__ logMessage("removing /mnt/usr/X11R6 symlink"); unlink("/mnt/usr/X11R6"); #endif handleSyslogSocket(rootPath); if (!upgrade) { #ifdef __sparc__ start_openprom(); #endif sprintf(path, "%s/etc/hosts", rootPath); fd = open(path, O_CREAT | O_RDWR, 0644); if (fd < 0) { errorWindow("Failed to create etc/hosts: %s."); return INST_ERROR; } write(fd, hostEntry, strlen(hostEntry)); close(fd); } sprintf(path, "%s/tmp/%s.log", rootPath, upgrade ? "upgrade" : "install"); lfFd = fdOpen(path, O_RDWR | O_CREAT | O_TRUNC, 0600); if (lfFd) { logFile = fdopen(fdFileno(lfFd), "w"); setlinebuf(logFile); logMessage("opened %s", path); } else { logMessage("failed to open %s :-(", path); newtWinMessage(_("Error"), _("Ok"), _("Failed to open %s. No upgrade log will be kept."), path); } rpmErrorSetCallback(rpmerror); /* FIXME: we ought to read /mnt/us/lib/rpmrc if we're in the midst of an upgrade, but it's not obvious how to get RPM to do that. */ /* if we set netshared path to "" then we get no files installed addMacro(&globalMacroContext, "_netsharedpath", NULL, netSharedPath ? netSharedPath : "" , RMIL_RPMRC); */ rpmdbInit(rootPath, 0644); if (rpmdbOpen(rootPath, &db, O_RDWR | O_CREAT, 0644)) { errorWindow(_("Fatal error opening RPM database")); return INST_ERROR; } logMessage("opened rpm database"); trans = rpmtransCreateSet(db, rootPath); for (i = 0; i < psp->numPackages; i++) { if (!strcmp(psp->packages[i]->name, "basesystem")) { rpmtransAddPackage(trans, psp->packages[i]->h, NULL, psp->packages[i], upgrade, NULL); } } totalNumPackages = 0, totalSizePackages = 0; for (i = 0; i < psp->numPackages; i++) { if (psp->packages[i]->selected) { if (strcmp(psp->packages[i]->name, "basesystem")) { rpmtransAddPackage(trans, psp->packages[i]->h, NULL, psp->packages[i], upgrade, NULL); } totalSizePackages += psp->packages[i]->size; totalNumPackages++; } } if (rpmdepOrder(trans)) { rpmdbClose(db); rpmtransFree(trans); newtWinMessage(_("Error"), _("Ok"), _("Error ordering package list: %s"), rpmErrorString()); return 1; } rpmtransSetScriptFd(trans, lfFd); cbi.step = -1; if (testing) { rpmtransFree(trans); newtWinMessage("Status", "Ok", "Packages would be installed now"); return 0; } cbi.method = method; cbi.upgrade = upgrade; cbi.totalnum = totalNumPackages; cbi.totalsize = totalSizePackages; si.packagesDone = -1; /* mount /proc in the instroot */ procPath = alloca(strlen(rootPath) + 50); sprintf(procPath, "%s/proc", rootPath); umount(procPath); if (doMount("/proc", procPath, "proc", 0, 0)) { return INST_ERROR; } if (rpmRunTransactions(trans, swCallback, &cbi, NULL, &probs, 0, ~RPMPROB_FILTER_DISKSPACE) && probs->numProblems) { char buf[2048], sbuf[100]; int i, last, rc, size; /* must not have enough disk space :-( */ qsort(probs->probs, probs->numProblems, sizeof(*probs->probs), probSort); strcpy(buf, _("You don't appear to have enough disk space to install " "the packages you've selected. You need more space on the " "following filesystems:\n\n")); size = 12; /* Minimum padding on filesystem */ for (i = 0; i < probs->numProblems; i++) { if (strlen(probs->probs[i].str1) > size) size = strlen(probs->probs[i].str1); } sprintf(sbuf, " %-*s %s\n", size, _("Mount Point"), _("Space Needed")); strcat(buf, sbuf); last = -1; for (i = 0; i < probs->numProblems; i++) { if (last == -1 || strcmp(probs->probs[last].str1, probs->probs[i].str1)) { path = probs->probs[i].str1; /* knock off the leading /mnt */ if (!strncmp("/mnt", path, 4)) path += 4; sprintf(sbuf, " %-*s %ld%c\n", size, path, probs->probs[i].ulong1 > (1024*1024) ? (probs->probs[i].ulong1 + 1024 * 1024 - 1) / (1024 * 1024) : (probs->probs[i].ulong1 + 1023) / 1024, probs->probs[i].ulong1 > (1024*1024) ? 'M' : 'k', probs->probs[i].ulong1); strcat(buf, sbuf); last = i; } } rpmProblemSetFree(probs); rc = newtWinChoice(_("Disk Space"), _("Back"), _("Install anyway"), buf); if (rc != 2) { rpmdbClose(db); rpmtransFree(trans); if (syncPid > 0) { kill(syncPid, SIGKILL); waitpid(syncPid, NULL, 0); } if (syslogPid > 0) { kill(syslogPid, SIGKILL); waitpid(syslogPid, NULL, 0); } fdClose(lfFd); umount(procPath); return INST_CANCEL; } rpmRunTransactions(trans, swCallback, &cbi, NULL, &probs, 0, ~0); } umount(procPath); if (syncPid > 0) { kill(syncPid, SIGKILL); waitpid(syncPid, NULL, 0); } fdClose(lfFd); swClose(); rpmProblemSetFree(probs); rpmtransFree(trans); rpmdbClose(db); logMessage("rpm database closed"); if (!upgrade) { sprintf(path, "%s/etc/sysconfig", rootPath); mkdir(path, 0755); writeKbdConfig(path, keymap, kbdtype); } if (!upgrade) { writeLangInfo(rootPath); } if (logFile) fclose(logFile); logFile = NULL; return 0; } int setupXfree(struct installMethod * method, char * rootPath, struct pkgSet * psp) { int fd, i; char buf[200], * chptr; char server[50]; int rc; char * path; char * procPath; rpmdb db; rpmTransactionSet trans; struct callbackInfo cbi; rpmProblemSet probs; if (rpmdbOpen(rootPath, &db, O_RDWR | O_CREAT, 0644)) { errorWindow(_("Fatal error reopening RPM database")); return INST_ERROR; } logMessage("reopened rpm database"); path = alloca(strlen(rootPath) + 200); procPath = alloca(strlen(rootPath) + 50); sprintf(path, "%s/usr/X11R6/bin/Xconfigurator", rootPath); /* This is a cheap trick to see if our X component was installed */ if (access(path, X_OK)) { logMessage("%s cannot be run", path); return INST_OKAY; } /* need proc to do pci probing */ sprintf(procPath, "%s/proc", rootPath); umount(procPath); if ((rc = doMount("/proc", procPath, "proc", 0, 0))) { return INST_ERROR; } /* this handles kickstart and normal/expert modes */ if ((rc=xfree86Config(rootPath, "--pick"))) return INST_ERROR; sprintf(path, "%s/tmp/SERVER", rootPath); if ((fd = open(path, O_RDONLY)) < 0) { logMessage("failed to open %s: %s", path, strerror(errno)); return INST_ERROR; } 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 %s", path); return INST_ERROR; } *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); trans = rpmtransCreateSet(db, rootPath); rpmtransAddPackage(trans, psp->packages[i]->h, NULL, psp->packages[i], 0, NULL); cbi.method = method; cbi.upgrade = 0; rpmRunTransactions(trans, swCallback, &cbi, NULL, &probs, 0, 0xffffffff); swClose(); break; } } /* this handles kickstart and normal/expert modes */ if ((rc=xfree86Config(rootPath, "--continue"))) return INST_ERROR; /* done with proc now */ umount(procPath); rpmdbClose(db); logMessage("rpm database closed"); return INST_OKAY; } 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 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 = 1; 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, ""); if (sizePackages) si.globalScale = newtScale(1, 13, 58, sizePackages); else si.globalScale = newtScale(1, 13, 58, 1); 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; if (si.packagesDone > si.numPackages) return; 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); si.packagesDone++; si.sizeDone += si.thisPackageSize; now = time(NULL); elapsedTime = now - si.timeStarted; formatTime(buf, elapsedTime); newtLabelSetText(si.timeDoneLabel, buf); if (si.sizeDone == 0) finishTime = 0; else 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 Header h, const rpmCallbackType what, const unsigned long amount, const unsigned long total, const void * pkgKey, void * data) { void * rc = NULL; struct callbackInfo * cbi = data; struct packageInfo * pkg = (void *) pkgKey; char * realName; int olderrno, i; int_32 *iptr; static int haveWindow = 0; struct { int num; char *desc; } descr[] = { { 1, _("Examining packages to install...")}, { 5, _("Examining files to install...")}, { 6, _("Finding overlapping files...")}, { -1, NULL } }; switch (what) { case RPMCALLBACK_TRANS_START: case RPMCALLBACK_UNINST_START: if (amount < 9) { i = 0; while(descr[i].num != -1 && descr[i].num != amount) i++; if (descr[i].num != -1 || what == RPMCALLBACK_UNINST_START) { newtCenteredWindow(60, 5, _("Processing")); haveWindow = 1; cbi->statusForm = newtForm(NULL, NULL, 0); newtFormAddComponent(cbi->statusForm, newtLabel(1, 1, what == RPMCALLBACK_TRANS_START ? descr[i].desc : _("Removing old files..."))); cbi->statusScale = newtScale(1, 3, 58, total); newtFormAddComponent(cbi->statusForm, cbi->statusScale); newtDrawForm(cbi->statusForm); newtRefresh(); } } break; case RPMCALLBACK_TRANS_PROGRESS: case RPMCALLBACK_UNINST_PROGRESS: if (haveWindow) { newtScaleSet(cbi->statusScale, amount); newtRefresh(); } break; case RPMCALLBACK_TRANS_STOP: case RPMCALLBACK_UNINST_STOP: if (haveWindow) { newtFormDestroy(cbi->statusForm); newtPopWindow(); haveWindow = 0; } break; case RPMCALLBACK_INST_START: swPackage(pkg->h); break; case RPMCALLBACK_INST_PROGRESS: if (total == 0) newtScaleSet(si.pkgScale, 100); else newtScaleSet(si.pkgScale, (amount * 100) / total); newtRefresh(); break; case RPMCALLBACK_INST_CLOSE_FILE: swPackageComplete(); fdClose(cbi->fd); if (cbi->method->rmFiles) unlink(cbi->lastFile); break; case RPMCALLBACK_INST_OPEN_FILE: if (si.packagesDone == -1) swOpen(cbi->totalnum, cbi->totalsize); if (logFile) fprintf(logFile, "%s %s.\n", cbi->upgrade ? _("Upgrading") : _("Installing"), pkg->name); swPackage(pkg->h); if (!headerGetEntry(pkg->h, FILESIZE_TAG, NULL, (void *) &iptr, NULL)) archiveSize = 0; else archiveSize = *iptr; if (cbi->method->getFile(cbi->method, pkg->data, &realName)) { logMessage("getFile method failed for %s", pkg->data); if (logFile) fprintf(logFile, "Failed to get file for package %s.\n", pkg->name); swPackageComplete(); return NULL; } cbi->fd = fdOpen(realName, O_RDONLY, 0666); if (!cbi->fd) { 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 NULL; } cbi->lastFile = realName; rc = cbi->fd; break; } return rc; } static void swClose(void) { if (si.packagesDone > 0) 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); } static int probSort(const void * one, const void * two) { const rpmProblem * a = one; const rpmProblem * b = two; int rc; rc = strcmp(a->str1, b->str1); if (rc) return rc; /* this puts the largest need at the top! */ if (a->ulong1 > b->ulong1) return -1; else if (a->ulong1 < b->ulong1) return 1; return 0; }