Пример #1
0
void loadLanguage(void)
{
    char *filename;
    int fd, hash, rc;
    char * key = getenv("LANGKEY");

    if (strings) {
        free(strings), strings = NULL;
        numStrings = allocedStrings = 0;
    }

    /* english requires no files */
    if (!strcmp(key, "en"))
        return;

    checked_asprintf(&filename, "/tmp/translation/%s.tr", key);

    rc = unpack_archive_file("/etc/loader.tr", "/tmp/translation");
    if (rc != ARCHIVE_OK || access("/tmp/translation", R_OK) == -1) {
        newtWinMessage("Error", "OK", "Cannot get translation file %s.\n",
                       filename);
        return;
    }

    fd = open(filename, O_RDONLY);
    if (fd < 0) {
        newtWinMessage("Error", "OK", "Failed to open /tmp/translation: %m\n");
        free(filename);
        return;
    }

    while (read(fd, &hash, 4) == 4) {
        if (allocedStrings == numStrings) {
            allocedStrings += 10;
            strings = realloc(strings, sizeof(*strings) * allocedStrings);
        }

        strings[numStrings].hash = ntohl(hash);
        rc = read(fd, &strings[numStrings].length, 2);
        strings[numStrings].length = ntohs(strings[numStrings].length);
        strings[numStrings].str = malloc(strings[numStrings].length + 1);
        rc = read(fd, strings[numStrings].str, strings[numStrings].length);
        strings[numStrings].str[strings[numStrings].length] = '\0';
        numStrings++;
    }

    close(fd);
    free(filename);
    int translation_dir_fd = open("/tmp/translation", O_RDONLY);
    recursiveRemove(translation_dir_fd);
    close(translation_dir_fd);
    rmdir("/tmp/translation");

    qsort(strings, numStrings, sizeof(*strings), aStringCmp);
}
Пример #2
0
/* @p path must be point to malloc'ed memory
 * Replaces **path with a pointer to a string containing
 * dirname + path.
 * path must be absolute.
 */
static int prepend_dir_to_name(const char *dirname, char **path)
{
    char *buf;
    checked_asprintf(&buf, "%s%s", dirname, *path);
    if (buf == NULL) {
            return EXIT_OUT_OF_MEMORY;
    }
    free(*path);
    *path = buf;
        return 0;
}
Пример #3
0
inline int cb_saveversions(gchar** parts, void *data0)
{
    GHashTable *ht = data0;
    gchar *module = g_strdup(parts[0]);
    char *versionfilename;
    char *srcversionfilename;
    gchar *version;
    gchar *srcversion;
    gchar *value, *value2;

    checked_asprintf(&versionfilename, "/sys/module/%s/version", module);
    checked_asprintf(&srcversionfilename, "/sys/module/%s/srcversion", module);

    /* emty string */
    value = g_new0(gchar, 1);

    /* get possible version file */
    if (g_file_get_contents(versionfilename, &version, NULL, NULL)) {
        value2 = g_strconcat(value, version, "/", NULL);
        g_free(value);
        g_free(version);
        value = value2;
    }

    /* get possible src version file */
    if (g_file_get_contents(srcversionfilename, &srcversion, NULL, NULL)) {
        value2 = g_strconcat(value, srcversion, NULL);
        g_free(value);
        g_free(srcversion);
        value = value2;
    }

    free(versionfilename);
    free(srcversionfilename);

    g_hash_table_insert(ht, module, value);

    return 1;
}
Пример #4
0
/**
 * Read in @p filename from inside @p dirname, and try to parse it as
 * a status file.
 *
 * If a new entry is read, a pointer to it is returned in @p lp.
 **/
static int dcc_mon_do_file(char *dirname, char *filename,
                           struct dcc_task_state **lp)
{
    int fd;
    char *fullpath;
    int ret;

    *lp = NULL;

    /* Is this a file we want to see */
    if (!str_startswith(dcc_state_prefix, filename)) {
/*         rs_trace("skipped"); */
        return 0;
    }

    checked_asprintf(&fullpath, "%s/%s", dirname, filename);
    if (fullpath == NULL) {
      return EXIT_OUT_OF_MEMORY;
    }
    rs_trace("process %s", fullpath);

    /* Remember that the file might disappear at any time, so open it
     * now so that we can hang on. */
    if ((fd = open(fullpath, O_RDONLY|O_BINARY, 0)) == -1) {
        if (errno == ENOENT) {
            rs_trace("%s disappeared", fullpath);
            ret = 0;
            goto out_free;
        } else { /* hm */
            rs_log_warning("failed to open %s: %s",
                           fullpath, strerror(errno));
            ret = EXIT_IO_ERROR;
            goto out_free;
        }
    }

    if ((ret = dcc_mon_kill_old(fd, fullpath))) {
        /* closes fd on failure */
        goto out_free;
    }

    ret = dcc_mon_load_state(fd, fullpath, lp);

    dcc_close(fd);

    out_free:
    free(fullpath);
    return ret;           /* ok */
}
Пример #5
0
/* choice is the index of the chosen language in languages */
static int setupLanguage(int choice, int forced) {
    char * buf;
    int i;

    logMessage(DEBUGLVL, "going to set language to %s", languages[choice].lc_all);
    /* load the language only if it is displayable.  if they're using
     * a serial console or iSeries vioconsole, we hope it's smart enough */
    if ((strcmp(languages[choice].font, "latarcyrheb-sun16") && !FL_SERIAL(flags) && 
         !FL_VIRTPCONSOLE(flags) && !isVioConsole())) {
        if (forced == 1) return 0;

	newtWinMessage("Language Unavailable", "OK", 
		       "%s display is unavailable in text mode.  The "
		       "installation will continue in English until the "
		       "display of %s is possible.", languages[choice].lang,
		       languages[choice].lang);
        setLangEnv(english);
	return 0;
    }
    
    setLangEnv (choice);
    isysLoadFont();

    /* clear out top line */
    buf = alloca(81); /* reserve one byte for \0 */
    for (i=0; i < 80; i++)
	buf[i] = ' ';
    buf[80] = 0; /* and set the \0 */
    newtDrawRootText(0, 0, buf);

    char *fmt = FL_RESCUE(flags) ? _(topLineWelcomeRescue) : _(topLineWelcome);
    checked_asprintf(&buf, fmt, getProductName(), getProductArch());

    newtDrawRootText(0, 0, buf);
    free(buf);
    newtPopHelpLine();
    newtPushHelpLine(_(bottomHelpLine));

    return 0;

}
Пример #6
0
/*
 * explode source RPM into the current directory
 * use filters to skip packages and files we do not need
 */
int explodeRPM(const char *source,
        filterfunc filter,
        dependencyfunc provides,
        dependencyfunc deps,
        void* userptr)
{
    char buffer[BUFFERSIZE+1]; /* make space for trailing \0 */
    FD_t fdi;
    Header h;
    char * rpmio_flags = NULL;
    rpmRC rc;
    FD_t gzdi;
    struct archive *cpio;
    struct archive_entry *cpio_entry;
    struct cpio_mydata cpio_mydata;

    rpmts ts;
    rpmVSFlags vsflags;
    const char *compr;

    if (strcmp(source, "-") == 0)
        fdi = fdDup(STDIN_FILENO);
    else
        fdi = Fopen(source, "r.ufdio");

    if (Ferror(fdi)) {
        const char *srcname = (strcmp(source, "-") == 0) ? "<stdin>" : source;
        logMessage(ERROR, "%s: %s\n", srcname, Fstrerror(fdi));
        return EXIT_FAILURE;
    }
    rpmReadConfigFiles(NULL, NULL);

    /* Initialize RPM transaction */
    ts = rpmtsCreate();
    vsflags = 0;

    /* Do not check digests, signatures or headers */
    vsflags |= _RPMVSF_NODIGESTS;
    vsflags |= _RPMVSF_NOSIGNATURES;
    vsflags |= RPMVSF_NOHDRCHK;
    (void) rpmtsSetVSFlags(ts, vsflags);

    rc = rpmReadPackageFile(ts, fdi, "rpm2dir", &h);

    ts = rpmtsFree(ts);

    switch (rc) {
        case RPMRC_OK:
        case RPMRC_NOKEY:
        case RPMRC_NOTTRUSTED:
            break;
        case RPMRC_NOTFOUND:
            logMessage(ERROR, "%s is not an RPM package", source);
            return EXIT_FAILURE;
            break;
        case RPMRC_FAIL:
        default:
            logMessage(ERROR, "error reading header from %s package\n", source);
            return EXIT_FAILURE;
            break;
    }

    /* Retrieve all dependencies and run them through deps function */
    while (deps) {
        struct rpmtd_s td;
        const char *depname;

        if (!headerGet(h, RPMTAG_REQUIRENAME, &td, HEADERGET_MINMEM))
            break;

        /* iterator */
        while ((depname = rpmtdNextString(&td))) {
            if (deps(depname, userptr)) {
                Fclose(fdi);
                return EXIT_BADDEPS;
            }
        }
        rpmtdFreeData(&td);
        break;
    }

    /* Retrieve all provides and run them through provides function */
    while (provides) {
        struct rpmtd_s td;
        const char *depname;
        int found = 0;

        if (!headerGet(h, RPMTAG_PROVIDES, &td, HEADERGET_MINMEM))
            break;

        /* iterator */
        while ((depname = rpmtdNextString(&td))) {
            if (!provides(depname, userptr)) {
                found++;
            }
        }
        rpmtdFreeData(&td);
        if (found<=0)
            return EXIT_BADDEPS;
        break;
    }

    /* Retrieve type of payload compression. */
    compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);
    if (compr && strcmp(compr, "gzip")) {
        checked_asprintf(&rpmio_flags, "r.%sdio", compr);
    }
    else {
        checked_asprintf(&rpmio_flags, "r.gzdio");
    }

    /* Open uncompressed cpio stream */
    gzdi = Fdopen(fdi, rpmio_flags);
    free(rpmio_flags);

    if (gzdi == NULL) {
        logMessage(ERROR, "cannot re-open payload: %s\n", Fstrerror(gzdi));
        return EXIT_FAILURE;
    }

    /* initialize cpio decompressor */
    cpio = archive_read_new();
    if (cpio==NULL) {
        Fclose(gzdi);
        return -1;
    }

    cpio_mydata.gzdi = gzdi;
    cpio_mydata.buffer = buffer;
    archive_read_support_compression_all(cpio);
    archive_read_support_format_all(cpio);
    rc = archive_read_open(cpio, &cpio_mydata, NULL, rpm_myread, rpm_myclose);

    /* check the status of archive_open */
    if (rc != ARCHIVE_OK){
        Fclose(gzdi);
        return -1;
    }

    /* read all files in cpio archive */
    while ((rc = archive_read_next_header(cpio, &cpio_entry)) == ARCHIVE_OK){
        const struct stat *fstat;
        int64_t fsize;
        const char* filename;
        int needskip = 1; /* do we need to read the data to get to the next header? */
        int offset = 0;
        int towrite = 0;

        filename = archive_entry_pathname(cpio_entry);
        fstat = archive_entry_stat(cpio_entry);
        fsize = archive_entry_size(cpio_entry);

        /* Strip leading slashes */
        while (filename[offset] == '/')
            offset+=1;

        /* Strip leading ./ */
        while (filename[offset] == '.' && filename[offset+1] == '/')
            offset+=2;

        /* Other file type - we do not care except special cases */
        if (!S_ISREG(fstat->st_mode))
            towrite = 1;
        else
            towrite = 2;

        if (filter && filter(filename+offset, fstat, userptr)) {
            /* filter this file */
            towrite = 0;
        }

        /* Create directories */
        char* dirname = strdup(filename+offset);

        /* If the dup fails, let's hope the dirs already exist */
        if (dirname){
            char* dirptr = dirname;
            while (dirptr && *dirptr) {
                dirptr = strchr(dirptr, '/');
                if (dirptr) {
                    *dirptr = 0;
                    mkdir(dirname, 0700);
                    *dirptr = '/';
                    dirptr++;
                }
            }
            free(dirname);
        }

        /* Regular file */
        if (towrite>=2) {
            FILE *fdout = fopen(filename+offset, "w");

            if (fdout==NULL){
                rc = 33;
                break;
            }
            
            rc = archive_read_data_into_fd(cpio, fileno(fdout));
            if (rc!=ARCHIVE_OK) {
                /* XXX We didn't get the file.. well.. */
                needskip = 0;
            } else {
                needskip = 0;
                fclose(fdout);
            }
        }

        /* symlink, we assume that the path contained in symlink
         * is shorter than BUFFERSIZE */
        while (towrite && S_ISLNK(fstat->st_mode)) {
            char symlinkbuffer[BUFFERSIZE-1];

            needskip = 0;
            if ((rc = archive_read_data(cpio, symlinkbuffer, fsize))!=ARCHIVE_OK) {
                /* XXX We didn't get the file.. well.. */
                break;
            }

            if (symlink(buffer, filename+offset)) {
                logMessage(ERROR, "Failed to create symlink %s -> %s", filename+offset, buffer);
            }

            break;
        }

        if(needskip)
            archive_read_data_skip(cpio);
    }

    archive_read_finish(cpio);

    return rc != ARCHIVE_OK;
}
Пример #7
0
/* Go through arguments (in @p argv), and relevant environment variables, and
 * find out where the dependencies output should go.  Return that location in a
 * newly allocated string in @p dotd_fname.  @p needs_dotd is set to true if the
 * compilation command line and environent imply that a .d file must be
 * produced.  @p sets_dotd_target is set to true if there is a -MQ or -MT
 * option.  This is to be used on the client, so that the client knows where to
 * put the .d file it gets from the server. @p dotd_target is set only if
 * @needs_dotd is true and @sets_dotd_target is false and the target is given in
 * the DEPENDENCIES_OUTPUT environment variable.
 *
 * Note: -M is not handled here, because this option implies -E.
 *
 * TODO(manos): it does not support SUNPRO_DEPENDENCIES.
 */
int dcc_get_dotd_info(char **argv, char **dotd_fname,
                      int *needs_dotd, int *sets_dotd_target,
                      char **dotd_target)
{
    char *deps_output = 0;

    char *input_file;
    char *output_file;
    char **new_args;  /* will throw this away */
    int has_dash_o = 0;
    char *env_var = 0;
    int ret;
    int i;
    char *a;

    *needs_dotd = 0;
    *sets_dotd_target = 0;
    *dotd_target = NULL;

    env_var = getenv("DEPENDENCIES_OUTPUT");

    if (env_var != NULL) {
        *needs_dotd = 1;
    }

    for (i = 0; (a = argv[i]); i++) {
        if (strcmp(a, "-MT") == 0) {
            *sets_dotd_target = 1;
            ++i;
            continue;
        }
        if (strcmp(a, "-MQ") == 0) {
            *sets_dotd_target = 1;
            ++i;
            continue;
        }
        /* Catch-all for all -MD, -MMD, etc, options.
         * -MQ and -MT do not imply a deps file is expected.
         */
        if (strncmp(a, "-M", 2) == 0) {
            *needs_dotd = 1;
        }
        if (strcmp(a, "-MF") == 0) {
            ++i;
            deps_output = argv[i];
        } else if (strncmp(a, "-MF", 3) == 0) {
            deps_output = argv[i] + 3;
        } else if (strcmp(a, "-o") == 0) {
            has_dash_o = 1;
        }
    }

    /* TODO(csilvers): we also need to parse -Wp,-x,-y,-z, in the same
     * way we do gcc flags in the for loop above.  Note that the -Wp
     * flags are passed to cpp, with slightly different semantics than
     * gcc flags (eg -Wp,-MD takes a filename argument, while -MD does
     * not).
     */

    if (deps_output) {
        *dotd_fname = strdup(deps_output);
        if (*dotd_fname == NULL) {
            return EXIT_OUT_OF_MEMORY;
        } else {
            return 0;
        }
    }

    /* ok, so there is no explicit setting of the deps filename. */
    deps_output = env_var;
    if (deps_output) {
        char *space;
        *dotd_fname = strdup(deps_output);
        if (*dotd_fname == NULL) {
            return EXIT_OUT_OF_MEMORY;
        }
        space = strchr(*dotd_fname, ' ');
        if (space != NULL) {
            *space = '\0';
            *dotd_target = space + 1;
        }

        return 0;
    }

    /* and it's not set explicitly in the variable */

    { /* Call dcc_scan_args to find the input/output files in order to calculate
         a name for the .d file.*/

        char *extension;
        char *tmp_dotd_fname;
        ret = dcc_scan_args(argv, &input_file, &output_file, &new_args, NULL);
        if (ret)
            return ret;
        /* if .o is set, just append .d.
         * otherwise, take the basename of the input, and set the suffix to .d */
        if (has_dash_o)
          tmp_dotd_fname = strdup(output_file);
        else
          tmp_dotd_fname = strdup(input_file);
        if (tmp_dotd_fname == NULL) return EXIT_OUT_OF_MEMORY;
        extension = dcc_find_extension(tmp_dotd_fname);
        /* Whether derived from input or output filename, we peel the extension
           off (if it exists). */
        if (extension) {
          /* dcc_find_extension guarantees that there is space for 'd'. */
          extension[1] = 'd';
          extension[2] = '\0';
          *dotd_fname = tmp_dotd_fname;
        }
        else { /* There is no extension (or name ends with a "."). */
          if (tmp_dotd_fname[strlen(tmp_dotd_fname) - 1] == '.')
            checked_asprintf(dotd_fname, "%s%s", tmp_dotd_fname, "d");
          else
            checked_asprintf(dotd_fname, "%s%s", tmp_dotd_fname, ".d");
          if (*dotd_fname == NULL) {
            return EXIT_OUT_OF_MEMORY;
          }
          free(tmp_dotd_fname);
        }
        return 0;
    }
}
Пример #8
0
/* given a partition device and directory, tries to mount hd install image */
static char * setupIsoImages(char * device, char * dirName, char * location) {
    int rc = 0;
    char *url = NULL, *dirspec, *updpath, *path;

    logMessage(INFO, "mounting device %s for hard drive install", device);

    if (doPwMount(device, "/mnt/isodir", "auto", "ro", NULL))
        return NULL;

    checked_asprintf(&dirspec, "/mnt/isodir%.*s",
                     (int) (strrchr(dirName, '/') - dirName), dirName);
    checked_asprintf(&path, "/mnt/isodir%s", dirName);

    if (path) {
        logMessage(INFO, "Path to stage2 image is %s", path);

        rc = copyFile(path, "/tmp/install.img");
        rc = mountStage2("/tmp/install.img");

        free(path);

        if (rc) {
            umountLoopback("/mnt/runtime", "/dev/loop0");
            umount("/mnt/isodir");
            goto err;
        }

        checked_asprintf(&updpath, "%s/updates.img", dirspec);

        logMessage(INFO, "Looking for updates for HD in %s", updpath);
        copyUpdatesImg(updpath);
        free(updpath);

        checked_asprintf(&updpath, "%s/product.img", dirspec);

        logMessage(INFO, "Looking for product for HD in %s", updpath);
        copyProductImg(updpath);

        free(updpath);
        free(dirspec);
        umount("/mnt/isodir");

        checked_asprintf(&url, "hd:%s:/%s", device,
                         dirName ? dirName : ".");

        return url;
    } else {
        free(dirspec);
        free(path);

        if (rc) {
            umount("/mnt/isodir");
            return NULL;
        }
    }

err:
    newtWinMessage(_("Error"), _("OK"),
                   _("An error occured finding the installation image "
                     "on your hard drive.  Please check your images and "
                     "try again."));
    return NULL;
}
Пример #9
0
/* setup hard drive based install from a partition with a filesystem and
 * ISO images on that filesystem
 */
char * mountHardDrive(struct installMethod * method,
		      char * location, struct loaderData_s * loaderData) {
    int rc;
    int i;

    newtComponent listbox, label, dirEntry, form, okay, back, text;
    struct newtExitStruct es;
    newtGrid entryGrid, grid, buttons;

    int done = 0;
    char * dir = strdup("");
    char * tmpDir;
    char * url = NULL;
    char * buf, *substr;
    int numPartitions;

    char **partition_list;
    char *selpart;
    char *kspartition = NULL, *ksdirectory = NULL;

    /* handle kickstart/stage2= data first if available */
    if (loaderData->method == METHOD_HD && loaderData->stage2Data) {
        kspartition = ((struct hdInstallData *)loaderData->stage2Data)->partition;
        ksdirectory = ((struct hdInstallData *)loaderData->stage2Data)->directory;
        logMessage(INFO, "partition is %s, dir is %s", kspartition, ksdirectory);

        /* if exist, duplicate */
        if (kspartition)
            kspartition = strdup(kspartition);
        if (ksdirectory) {
            ksdirectory = strdup(ksdirectory);
        } else {
            ksdirectory = strdup("/images/install.img");
        }

        if (!kspartition || !ksdirectory) {
            logMessage(ERROR, "missing partition or directory specification");
            loaderData->method = -1;

            if (loaderData->inferredStage2)
                loaderData->invalidRepoParam = 1;
        } else {
            /* if we start with /dev, strip it (#121486) */
            char *kspart = kspartition;
            if (!strncmp(kspart, "/dev/", 5))
                kspart = kspart + 5;

            url = setupIsoImages(kspart, ksdirectory, location);
            if (!url) {
                logMessage(ERROR, "unable to find %s installation images on hd",
                           getProductName());
                loaderData->method = -1;

                if (loaderData->inferredStage2)
                    loaderData->invalidRepoParam = 1;
            } else {
                free(kspartition);
                free(ksdirectory);
                return url;
            }
        }
    } else {
        kspartition = NULL;
        ksdirectory = NULL;
    }

    /* if we're here its either because this is interactive, or the */
    /* hd kickstart directive was faulty and we have to prompt for  */
    /* location of harddrive image                                  */

    partition_list = NULL;
    while (!done) {
        /* if we're doing another pass free this up first */
        if (partition_list)
            freePartitionsList(partition_list);

        partition_list = getPartitionsList(NULL);
        numPartitions = lenPartitionsList(partition_list);

        /* no partitions found, try to load a device driver disk for storage */
        if (!numPartitions) {
            rc = newtWinChoice(_("Hard Drives"), _("Yes"), _("Back"),
                               _("You don't seem to have any hard drives on "
                                 "your system! Would you like to configure "
                                 "additional devices?"));
            if (rc == 2) {
                loaderData->stage2Data = NULL;
                return NULL;
            }

            rc = loadDriverFromMedia(DEVICE_DISK, loaderData, 0, 0);
            continue;
        }

        /* now find out which partition has the stage2 image */
        checked_asprintf(&buf, _("What partition and directory on that "
                                 "partition holds the installation image "
                                 "for %s?  If you don't see the disk drive "
                                 "you're using listed here, press F2 to "
                                 "configure additional devices."),
                         getProductName());

        text = newtTextboxReflowed(-1, -1, buf, 62, 5, 5, 0);
        free(buf);

        listbox = newtListbox(-1, -1, numPartitions > 5 ? 5 : numPartitions,
                              NEWT_FLAG_RETURNEXIT | 
                              (numPartitions > 5 ? NEWT_FLAG_SCROLL : 0));

        for (i = 0; i < numPartitions; i++)
            newtListboxAppendEntry(listbox,partition_list[i],partition_list[i]);

        /* if we had ks data around use it to prime entry, then get rid of it*/
        if (kspartition) {
            newtListboxSetCurrentByKey(listbox, kspartition);
            free(kspartition);
            kspartition = NULL;
        }

        label = newtLabel(-1, -1, _("Directory holding image:"));

        dirEntry = newtEntry(28, 11, dir, 28, (const char **) &tmpDir,
                             NEWT_ENTRY_SCROLL);

        /* if we had ks data around use it to prime entry, then get rid of it*/
        if (ksdirectory) {
            newtEntrySet(dirEntry, ksdirectory, 1);
            free(ksdirectory);
            ksdirectory = NULL;
        }

        entryGrid = newtGridHStacked(NEWT_GRID_COMPONENT, label,
                                     NEWT_GRID_COMPONENT, dirEntry,
                                     NEWT_GRID_EMPTY);

        buttons = newtButtonBar(_("OK"), &okay, _("Back"), &back, NULL);

        grid = newtCreateGrid(1, 4);
        newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
                         0, 0, 0, 1, 0, 0);
        newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, listbox,
                         0, 0, 0, 1, 0, 0);
        newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, entryGrid,
                         0, 0, 0, 1, 0, 0);
        newtGridSetField(grid, 0, 3, NEWT_GRID_SUBGRID, buttons,
                         0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX);

        newtGridWrappedWindow(grid, _("Select Partition"));

        form = newtForm(NULL, NULL, 0);
        newtFormAddHotKey(form, NEWT_KEY_F2);
        newtFormAddHotKey(form, NEWT_KEY_F12);

        newtGridAddComponentsToForm(grid, form, 1);
        newtGridFree(grid, 1);

        newtFormRun(form, &es);

        selpart = newtListboxGetCurrent(listbox);

        free(dir);
        if (tmpDir && *tmpDir) {
            /* Protect from form free. */
            dir = strdup(tmpDir);
        } else  {
            dir = strdup("");
        }

        newtFormDestroy(form);
        newtPopWindow();

        if (es.reason == NEWT_EXIT_COMPONENT && es.u.co == back) {
            loaderData->stage2Data = NULL;
            return NULL;
        } else if (es.reason == NEWT_EXIT_HOTKEY && es.u.key == NEWT_KEY_F2) {
            rc = loadDriverFromMedia(DEVICE_DISK, loaderData, 0, 0);
            continue;
        }

        logMessage(INFO, "partition %s selected", selpart);

        /* If the user-provided URL points at a repo instead of a stage2
         * image, fix that up now.
         */
        substr = strstr(dir, ".img");
        if (!substr || (substr && *(substr+4) != '\0')) {
            checked_asprintf(&dir, "%s/images/install.img", dir);
        }

        loaderData->invalidRepoParam = 1;

        url = setupIsoImages(selpart, dir, location);
        if (!url) {
            newtWinMessage(_("Error"), _("OK"), 
                           _("Device %s does not appear to contain "
                             "an installation image."), selpart, getProductName());
            continue;
        }

        done = 1; 
    }

    free(dir);

    return url;
}