summaryrefslogtreecommitdiffstats
path: root/loader/method.c
diff options
context:
space:
mode:
authorDavid Cantrell <dcantrell@redhat.com>2008-08-25 17:13:37 -1000
committerDavid Cantrell <dcantrell@redhat.com>2008-08-25 17:13:37 -1000
commit80713e3f73e48856221c667f32b94b0a023ebecc (patch)
treeaff4d9170fc24d2f1acc238a2d8908159a71d3dd /loader/method.c
parentef5fbf7bc72572f3a6326b12f9187a5438e58e4c (diff)
downloadanaconda-80713e3f73e48856221c667f32b94b0a023ebecc.tar.gz
anaconda-80713e3f73e48856221c667f32b94b0a023ebecc.tar.xz
anaconda-80713e3f73e48856221c667f32b94b0a023ebecc.zip
Renamed loader2 subdirectory to loader (hooray for git)
Diffstat (limited to 'loader/method.c')
-rw-r--r--loader/method.c540
1 files changed, 540 insertions, 0 deletions
diff --git a/loader/method.c b/loader/method.c
new file mode 100644
index 000000000..26dc2c3fa
--- /dev/null
+++ b/loader/method.c
@@ -0,0 +1,540 @@
+/*
+ * method.c - generic install method setup functions
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt@redhat.com>
+ * Matt Wilson <msw@redhat.com>
+ * Michael Fulbright <msf@redhat.com>
+ * Jeremy Katz <katzj@redhat.com>
+ */
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <libgen.h>
+
+#include "copy.h"
+#include "loader.h"
+#include "loadermisc.h"
+#include "log.h"
+#include "lang.h"
+#include "mediacheck.h"
+#include "method.h"
+
+#include "../isys/imount.h"
+#include "../isys/isys.h"
+#include "../isys/cpio.h"
+
+#include "devt.h"
+
+#include "nfsinstall.h"
+#include "hdinstall.h"
+#include "urlinstall.h"
+
+/* boot flags */
+extern uint64_t flags;
+
+int umountLoopback(char * mntpoint, char * device) {
+ int loopfd;
+
+ umount(mntpoint);
+
+ logMessage(INFO, "umounting loopback %s %s", mntpoint, device);
+
+ loopfd = open(device, O_RDONLY);
+
+ if (ioctl(loopfd, LOOP_CLR_FD, 0) == -1)
+ logMessage(ERROR, "LOOP_CLR_FD failed for %s %s: %m", mntpoint, device);
+
+ close(loopfd);
+
+ return 0;
+}
+
+int mountLoopback(char *fsystem, char *mntpoint, char *device) {
+ char *opts;
+
+ if (device == NULL) {
+ logMessage(ERROR, "no loopback device given");
+ return LOADER_ERROR;
+ }
+
+ if (access(fsystem, F_OK) != 0) {
+ logMessage(ERROR, "file %s is not accessible", fsystem);
+ return LOADER_ERROR;
+ }
+
+ if (asprintf(&opts, "ro,loop=%s", device) == -1) {
+ logMessage(CRITICAL, "%s: %d: %m", __func__, __LINE__);
+ abort();
+ }
+
+ if (doPwMount(fsystem, mntpoint, "iso9660", opts, NULL)) {
+ if (doPwMount(fsystem, mntpoint, "ext2", opts, NULL)) {
+ if (doPwMount(fsystem, mntpoint, "squashfs", opts, NULL)) {
+ if (doPwMount(fsystem, mntpoint, "cramfs", opts, NULL)) {
+ if (doPwMount(fsystem, mntpoint, "vfat", opts, NULL)) {
+ logMessage(ERROR, "failed to mount loopback device %s on %s as %s: %m",
+ device, mntpoint, fsystem);
+ return LOADER_ERROR;
+ }
+ }
+ }
+ }
+ }
+
+ logMessage(INFO, "mounted loopback device %s on %s as %s", mntpoint, device, fsystem);
+
+ return 0;
+}
+
+/* returns the *absolute* path (malloced) to the #1 iso image */
+/* get timestamp and description of ISO image from stamp file */
+/* returns 0 on success, -1 otherwise */
+int readStampFileFromIso(char *file, char **timestamp, char **releasedescr) {
+ DIR * dir;
+ FILE *f;
+ struct dirent * ent;
+ struct stat sb;
+ char *stampfile;
+ char *descr, *tstamp;
+ char tmpstr[1024];
+ int filetype;
+ int rc;
+
+ lstat(file, &sb);
+ if (S_ISBLK(sb.st_mode)) {
+ filetype = 1;
+ if (doPwMount(file, "/tmp/testmnt", "iso9660", "ro", NULL)) {
+ logMessage(ERROR, "Failed to mount device %s to get description",
+ file);
+ return -1;
+ }
+ } else if (S_ISREG(sb.st_mode)) {
+ filetype = 2;
+ if (mountLoopback(file, "/tmp/testmnt", "/dev/loop6")) {
+ logMessage(ERROR, "Failed to mount iso %s to get description",
+ file);
+ return -1;
+ }
+ } else {
+ logMessage(ERROR, "Unknown type of file %s to get description",
+ file);
+ return -1;
+ }
+
+ if (!(dir = opendir("/tmp/testmnt"))) {
+ umount("/tmp/testmnt");
+ if (filetype == 2)
+ umountLoopback("/tmp/testmnt", "/dev/loop6");
+ return -1;
+ }
+
+ errno = 0;
+ stampfile = NULL;
+ while ((ent = readdir(dir))) {
+ if (!strncmp(ent->d_name, ".discinfo", 9)) {
+ stampfile = strdup(".discinfo");
+ break;
+ }
+ }
+
+ closedir(dir);
+ descr = NULL;
+ tstamp = NULL;
+ if (stampfile) {
+ snprintf(tmpstr, sizeof(tmpstr), "/tmp/testmnt/%s", stampfile);
+ f = fopen(tmpstr, "r");
+ if (f) {
+ char *tmpptr;
+
+ /* readtime stamp line */
+ tmpptr = fgets(tmpstr, sizeof(tmpstr), f);
+
+ if (tmpptr)
+ tstamp = strdup(tmpstr);
+
+ /* now read OS description line */
+ if (tmpptr)
+ tmpptr = fgets(tmpstr, sizeof(tmpstr), f);
+
+ if (tmpptr)
+ descr = strdup(tmpstr);
+
+ /* skip over arch */
+ if (tmpptr)
+ tmpptr = fgets(tmpstr, sizeof(tmpstr), f);
+
+ /* now get the CD number */
+ if (tmpptr) {
+ unsigned int len;
+ char *p, *newstr;
+
+ tmpptr = fgets(tmpstr, sizeof(tmpstr), f);
+
+ /* nuke newline from end of descr, stick number on end*/
+ for (p=descr+strlen(descr); p != descr && !isspace(*p); p--);
+
+ *p = '\0';
+ len = strlen(descr) + strlen(tmpstr) + 10;
+ newstr = malloc(len);
+ strncpy(newstr, descr, len-1);
+ strncat(newstr, " ", len-1);
+
+ /* is this a DVD or not? If disc id has commas, like */
+ /* "1,2,3", its a DVD */
+ if (strchr(tmpstr, ','))
+ strncat(newstr, "DVD\n", len-1);
+ else {
+ strncat(newstr, "disc ", len-1);
+ strncat(newstr, tmpstr, len-1);
+ }
+
+ free(descr);
+ descr = newstr;
+ }
+
+ fclose(f);
+ }
+ }
+
+ free(stampfile);
+
+ umount("/tmp/testmnt");
+ if (filetype == 2)
+ umountLoopback("/tmp/testmnt", "/dev/loop6");
+
+ if (descr != NULL && tstamp != NULL) {
+ descr[strlen(descr)-1] = '\0';
+ *releasedescr = descr;
+
+ tstamp[strlen(tstamp)-1] = '\0';
+ *timestamp = tstamp;
+
+ rc = 0;
+ } else {
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/* XXX this ignores "location", which should be fixed
+ *
+ * Given a starting isoFile, will offer choice to mediacheck it and
+ * all other ISO images in the same directory with the same stamp
+ */
+void queryIsoMediaCheck(char *isoFile) {
+ DIR * dir;
+ struct dirent * ent;
+ char *isoDir;
+ char isoImage[1024];
+ char tmpmessage[1024];
+ char *master_timestamp;
+ char *tmpstr;
+ int rc, first;
+
+ /* dont bother to test in automated installs */
+ if (FL_KICKSTART(flags) && !FL_MEDIACHECK(flags))
+ return;
+
+ /* if they did not specify to mediacheck explicitely then return */
+ if (!FL_MEDIACHECK(flags))
+ return;
+
+ /* check that file is actually an iso */
+ if (!fileIsIso(isoFile))
+ return;
+
+ /* get stamp of isoFile, free descr since we dont care */
+ readStampFileFromIso(isoFile, &master_timestamp, &tmpstr);
+ free(tmpstr);
+
+ /* get base path from isoFile */
+ tmpstr = strdup(isoFile);
+ isoDir = strdup(dirname(tmpstr));
+ free(tmpstr);
+
+ logMessage(DEBUGLVL, "isoFile = %s", isoFile);
+ logMessage(DEBUGLVL, "isoDir = %s", isoDir);
+ logMessage(DEBUGLVL, "Master Timestemp = %s", master_timestamp);
+
+ if (!(dir = opendir(isoDir))) {
+ newtWinMessage(_("Error"), _("OK"),
+ _("Failed to read directory %s: %m"),
+ isoDir);
+ free(isoDir);
+ free(master_timestamp);
+ return;
+ }
+
+ /* Walk through the directories looking for a CD images. */
+ errno = 0;
+ first = 0;
+ while (1) {
+ char *nextname;
+ char *tdescr, *tstamp;
+
+ if (first) {
+ first = 1;
+ nextname = isoFile;
+ } else {
+ ent = readdir(dir);
+ if (!ent)
+ break;
+
+ nextname = ent->d_name;
+ }
+
+ /* synthesize name of iso from isoDir and file entry */
+ snprintf(isoImage, sizeof(isoImage), "%s/%s", isoDir, nextname);
+
+ /* see if this is an iso image */
+ if (!fileIsIso(isoImage)) {
+ errno = 0;
+ continue;
+ }
+
+ /* see if its part of the current CD set */
+ readStampFileFromIso(isoImage, &tstamp, &tdescr);
+ if (strcmp(tstamp, master_timestamp)) {
+ errno = 0;
+ continue;
+ }
+
+ /* found a valid candidate, proceed */
+ snprintf(tmpmessage, sizeof(tmpmessage),
+ _("Would you like to perform a checksum "
+ "test of the ISO image:\n\n %s?"), isoImage);
+
+ rc = newtWinChoice(_("Checksum Test"), _("Test"), _("Skip"),
+ tmpmessage);
+
+ if (rc == 2) {
+ logMessage(INFO, "mediacheck: skipped checking of %s", isoImage);
+ if (tdescr)
+ free(tdescr);
+ continue;
+ } else {
+ doMediaCheck(isoImage, tdescr);
+ if (tdescr)
+ free(tdescr);
+
+ continue;
+ }
+ }
+
+ free(isoDir);
+ free(master_timestamp);
+ closedir(dir);
+}
+
+static void copyWarnFn (char *msg) {
+ logMessage(WARNING, msg);
+}
+
+static void copyErrorFn (char *msg) {
+ newtWinMessage(_("Error"), _("OK"), _(msg));
+}
+
+/*
+ * unpack a gzipped cpio ball into a tree rooted at rootDir
+ * returns 0 on success, 1 on failure
+ */
+int unpackCpioBall(char * ballPath, char * rootDir) {
+ gzFile fd;
+ char *buf, *cwd;
+ int rc = 1;
+
+ if (access(ballPath, R_OK))
+ return 1;
+
+ if (access(rootDir, R_OK))
+ mkdirChain(rootDir);
+
+ buf = (char *)malloc(PATH_MAX);
+ cwd = getcwd(buf, PATH_MAX);
+ if ((rc = chdir(rootDir)) == 0) {
+ fd = gunzip_open(ballPath);
+ if (fd) {
+ if (!installCpioFile(fd, NULL, NULL, 0)) {
+ logMessage(INFO, "copied contents of %s into %s", ballPath,
+ rootDir);
+ rc = chdir(cwd);
+ return 0;
+ }
+ gunzip_close(fd);
+ }
+ rc = chdir(cwd);
+ }
+
+ return 1;
+}
+
+void copyUpdatesImg(char * path) {
+ if (!access(path, R_OK)) {
+ if (!mountLoopback(path, "/tmp/update-disk", "/dev/loop7")) {
+ copyDirectory("/tmp/update-disk", "/tmp/updates", copyWarnFn,
+ copyErrorFn);
+ umountLoopback("/tmp/update-disk", "/dev/loop7");
+ unlink("/tmp/update-disk");
+ } else {
+ unpackCpioBall(path, "/tmp/updates");
+ }
+ }
+}
+
+void copyProductImg(char * path) {
+ if (!access(path, R_OK)) {
+ if (!mountLoopback(path, "/tmp/product-disk", "/dev/loop7")) {
+ copyDirectory("/tmp/product-disk", "/tmp/product", copyWarnFn,
+ copyErrorFn);
+ umountLoopback("/tmp/product-disk", "/dev/loop7");
+ unlink("/tmp/product-disk");
+ }
+ }
+}
+
+/* unmount a second stage, if mounted. Used for CDs and mediacheck mostly,
+ so we can eject CDs. */
+void umountStage2(void) {
+ umountLoopback("/mnt/runtime", "/dev/loop0");
+}
+
+/* mount a second stage, verify the stamp file, copy updates
+ * Returns 0 on success, 1 on failure to mount, -1 on bad stamp */
+int mountStage2(char *stage2path) {
+ if (access(stage2path, R_OK)) {
+ return 1;
+ }
+
+ if (mountLoopback(stage2path, "/mnt/runtime", "/dev/loop0")) {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* copies a second stage from fd to dest and mounts on mntpoint */
+int copyFileAndLoopbackMount(int fd, char * dest,
+ char * device, char * mntpoint) {
+ int rc;
+ struct stat sb;
+
+ rc = copyFileFd(fd, dest);
+ stat(dest, &sb);
+ logMessage(DEBUGLVL, "copied %" PRId64 " bytes to %s (%s)", sb.st_size, dest,
+ ((rc) ? " incomplete" : "complete"));
+
+ if (rc) {
+ /* just to make sure */
+ unlink(dest);
+ return 1;
+ }
+
+ if (mountLoopback(dest, mntpoint, device)) {
+ /* JKFIXME: this used to be fatal, but that seems unfriendly */
+ logMessage(ERROR, "Error mounting %s on %s: %m", device, mntpoint);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* given a device name (w/o '/dev' on it), try to get a file */
+/* Error codes:
+ 1 - could not create device node
+ 2 - could not mount device as ext2, vfat, or iso9660
+ 3 - file named path not there
+*/
+int getFileFromBlockDevice(char *device, char *path, char * dest) {
+ int rc;
+ char file[4096];
+
+ logMessage(INFO, "getFileFromBlockDevice(%s, %s)", device, path);
+
+ if (doPwMount(device, "/tmp/mnt", "vfat", "ro", NULL) &&
+ doPwMount(device, "/tmp/mnt", "ext2", "ro", NULL) &&
+ doPwMount(device, "/tmp/mnt", "iso9660", "ro", NULL)) {
+ logMessage(ERROR, "failed to mount /dev/%s: %m", device);
+ return 2;
+ }
+
+ snprintf(file, sizeof(file), "/tmp/mnt/%s", path);
+ logMessage(INFO, "Searching for file on path %s", file);
+
+ if (access(file, R_OK)) {
+ rc = 3;
+ } else {
+ copyFile(file, dest);
+ rc = 0;
+ logMessage(INFO, "file copied to %s", dest);
+ }
+
+ umount("/tmp/mnt");
+ unlink("/tmp/mnt");
+ return rc;
+}
+
+void setStage2LocFromCmdline(char * arg, struct loaderData_s * ld) {
+ char * c, * dup;
+
+ dup = strdup(arg);
+ c = dup;
+ /* : will let us delimit real information on the method */
+ if ((c = strtok(c, ":"))) {
+ c = strtok(NULL, ":");
+
+ if (!strncmp(arg, "nfs:", 4)) {
+ ld->method = METHOD_NFS;
+ ld->stage2Data = calloc(sizeof(struct nfsInstallData *), 1);
+
+ ((struct nfsInstallData *)ld->stage2Data)->mountOpts = NULL;
+ ((struct nfsInstallData *)ld->stage2Data)->host = strdup(c);
+ if ((c = strtok(NULL, ":"))) {
+ ((struct nfsInstallData *)ld->stage2Data)->directory = strdup(c);
+ }
+ } else if (!strncmp(arg, "ftp:", 4) ||
+ !strncmp(arg, "http:", 5)) {
+ ld->method = METHOD_URL;
+ ld->stage2Data = calloc(sizeof(struct urlInstallData *), 1);
+ ((struct urlInstallData *)ld->stage2Data)->url = strdup(arg);
+ } else if (!strncmp(arg, "cdrom:", 6)) {
+ ld->method = METHOD_CDROM;
+ } else if (!strncmp(arg, "harddrive:", 10) ||
+ !strncmp(arg, "hd:", 3)) {
+ ld->method = METHOD_HD;
+ ld->stage2Data = calloc(sizeof(struct hdInstallData *), 1);
+ ((struct hdInstallData *)ld->stage2Data)->partition = strdup(c);
+ if ((c = strtok(NULL, ":"))) {
+ ((struct hdInstallData *)ld->stage2Data)->directory = strdup(c);
+ }
+ }
+ }
+ free(dup);
+}