Date: Mon, 1 Jun 2015 01:06:34 +0000 (UTC) From: Devin Teske <dteske@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r283859 - in stable/10/usr.sbin/bsdinstall: distextract distfetch Message-ID: <201506010106.t5116Ypt006992@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: dteske Date: Mon Jun 1 01:06:33 2015 New Revision: 283859 URL: https://svnweb.freebsd.org/changeset/base/283859 Log: MFC SVN revisions 272278,272379,275874: r272278: Prevent buffer overflow(s) + style(9) nits r272379: Optimize program performance + style(9) nits r275874: Improve feedback to user by using dpv(3) Modified: stable/10/usr.sbin/bsdinstall/distextract/Makefile stable/10/usr.sbin/bsdinstall/distextract/distextract.c stable/10/usr.sbin/bsdinstall/distfetch/distfetch.c Directory Properties: stable/10/ (props changed) Modified: stable/10/usr.sbin/bsdinstall/distextract/Makefile ============================================================================== --- stable/10/usr.sbin/bsdinstall/distextract/Makefile Mon Jun 1 00:55:15 2015 (r283858) +++ stable/10/usr.sbin/bsdinstall/distextract/Makefile Mon Jun 1 01:06:33 2015 (r283859) @@ -2,8 +2,8 @@ BINDIR= /usr/libexec/bsdinstall PROG= distextract -DPADD= ${LIBARCHIVE} ${LIBDIALOG} ${LIBM} -LDADD= -larchive -ldialog -lm +DPADD= ${LIBARCHIVE} ${LIBDPV} ${LIBFIGPAR} ${LIBDIALOG} ${LIBM} +LDADD= -larchive -ldpv -lfigpar -ldialog -lm WARNS?= 6 MAN= Modified: stable/10/usr.sbin/bsdinstall/distextract/distextract.c ============================================================================== --- stable/10/usr.sbin/bsdinstall/distextract/distextract.c Mon Jun 1 00:55:15 2015 (r283858) +++ stable/10/usr.sbin/bsdinstall/distextract/distextract.c Mon Jun 1 01:06:33 2015 (r283859) @@ -1,5 +1,6 @@ /*- * Copyright (c) 2011 Nathan Whitehorn + * Copyright (c) 2014 Devin Teske <dteske@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,118 +23,231 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + #include <sys/param.h> -#include <stdio.h> -#include <errno.h> -#include <limits.h> #include <archive.h> +#include <ctype.h> #include <dialog.h> +#include <dpv.h> +#include <err.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +/* Data to process */ +static char *distdir = NULL; +static struct archive *archive = NULL; +static struct dpv_file_node *dists = NULL; + +/* Function prototypes */ +static void sig_int(int sig); +static int count_files(const char *file); +static int extract_files(struct dpv_file_node *file, int out); + +#if __FreeBSD_version <= 1000008 /* r232154: bump for libarchive update */ +#define archive_read_support_filter_all(x) \ + archive_read_support_compression_all(x) +#endif -static int extract_files(int nfiles, const char **files); +#define _errx(...) (end_dialog(), errx(__VA_ARGS__)) int main(void) { - char *diststring; - const char **dists; - int i, retval, ndists = 0; - - if (getenv("DISTRIBUTIONS") == NULL) { - fprintf(stderr, "DISTRIBUTIONS variable is not set\n"); - return (1); - } - - diststring = strdup(getenv("DISTRIBUTIONS")); - for (i = 0; diststring[i] != 0; i++) - if (isspace(diststring[i]) && !isspace(diststring[i+1])) - ndists++; - ndists++; /* Last one */ - - dists = calloc(ndists, sizeof(const char *)); - if (dists == NULL) { - fprintf(stderr, "Out of memory!\n"); - free(diststring); - return (1); - } - - for (i = 0; i < ndists; i++) - dists[i] = strsep(&diststring, " \t"); + char *chrootdir; + char *distributions; + int retval; + size_t config_size = sizeof(struct dpv_config); + size_t file_node_size = sizeof(struct dpv_file_node); + size_t span; + struct dpv_config *config; + struct dpv_file_node *dist = dists; + static char backtitle[] = "FreeBSD Installer"; + static char title[] = "Archive Extraction"; + static char aprompt[] = "\n Overall Progress:"; + static char pprompt[] = "Extracting distribution files...\n"; + struct sigaction act; + char error[PATH_MAX + 512]; + + if ((distributions = getenv("DISTRIBUTIONS")) == NULL) + errx(EXIT_FAILURE, "DISTRIBUTIONS variable is not set"); + if ((distdir = getenv("BSDINSTALL_DISTDIR")) == NULL) + distdir = __DECONST(char *, ""); + /* Initialize dialog(3) */ init_dialog(stdin, stdout); - dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer"); + dialog_vars.backtitle = backtitle; dlg_put_backtitle(); - if (chdir(getenv("BSDINSTALL_CHROOT")) != 0) { - char error[512]; - sprintf(error, "Could could change to directory %s: %s\n", - getenv("BSDINSTALL_DISTDIR"), strerror(errno)); + dialog_msgbox("", + "Checking distribution archives.\nPlease wait...", 4, 35, FALSE); + + /* + * Parse $DISTRIBUTIONS into dpv(3) linked-list + */ + while (*distributions != '\0') { + span = strcspn(distributions, "\t\n\v\f\r "); + if (span < 1) { /* currently on whitespace */ + distributions++; + continue; + } + + /* Allocate a new struct for the distribution */ + if (dist == NULL) { + if ((dist = calloc(1, file_node_size)) == NULL) + _errx(EXIT_FAILURE, "Out of memory!"); + dists = dist; + } else { + dist->next = calloc(1, file_node_size); + if (dist->next == NULL) + _errx(EXIT_FAILURE, "Out of memory!"); + dist = dist->next; + } + + /* Set path */ + if ((dist->path = malloc(span + 1)) == NULL) + _errx(EXIT_FAILURE, "Out of memory!"); + snprintf(dist->path, span + 1, "%s", distributions); + dist->path[span] = '\0'; + + /* Set display name */ + dist->name = strrchr(dist->path, '/'); + if (dist->name == NULL) + dist->name = dist->path; + + /* Set initial length in files (-1 == error) */ + dist->length = count_files(dist->path); + if (dist->length < 0) { + end_dialog(); + return (EXIT_FAILURE); + } + + distributions += span; + } + + /* Optionally chdir(2) into $BSDINSTALL_CHROOT */ + chrootdir = getenv("BSDINSTALL_CHROOT"); + if (chrootdir != NULL && chdir(chrootdir) != 0) { + snprintf(error, sizeof(error), + "Could not change to directory %s: %s\n", + chrootdir, strerror(errno)); dialog_msgbox("Error", error, 0, 0, TRUE); end_dialog(); - return (1); + return (EXIT_FAILURE); } - retval = extract_files(ndists, dists); - + /* Set cleanup routine for Ctrl-C action */ + act.sa_handler = sig_int; + sigaction(SIGINT, &act, 0); + + /* + * Hand off to dpv(3) + */ + if ((config = calloc(1, config_size)) == NULL) + _errx(EXIT_FAILURE, "Out of memory!"); + config->backtitle = backtitle; + config->title = title; + config->pprompt = pprompt; + config->aprompt = aprompt; + config->options |= DPV_WIDE_MODE; + config->label_size = -1; + config->action = extract_files; + config->status_solo = + "%10lli files read @ %'9.1f files/sec."; + config->status_many = + "%10lli files read @ %'9.1f files/sec. [%i/%i busy/wait]"; end_dialog(); + retval = dpv(config, dists); - free(diststring); - free(dists); + dpv_free(); + while ((dist = dists) != NULL) { + dists = dist->next; + if (dist->path != NULL) + free(dist->path); + free(dist); + } return (retval); } +static void +sig_int(int sig __unused) +{ + dpv_interrupt = TRUE; +} + +/* + * Returns number of files in archive file. Parses $BSDINSTALL_DISTDIR/MANIFEST + * if it exists, otherwise uses archive(3) to read the archive file. + */ static int count_files(const char *file) { - struct archive *archive; - struct archive_entry *entry; static FILE *manifest = NULL; - char path[MAXPATHLEN]; - char errormsg[512]; - int file_count, err; + char *p; + int file_count; + int retval; + size_t span; + struct archive_entry *entry; + char line[512]; + char path[PATH_MAX]; + char errormsg[PATH_MAX + 512]; if (manifest == NULL) { - sprintf(path, "%s/MANIFEST", getenv("BSDINSTALL_DISTDIR")); + snprintf(path, sizeof(path), "%s/MANIFEST", distdir); manifest = fopen(path, "r"); } if (manifest != NULL) { - char line[512]; - char *tok1, *tok2; - rewind(manifest); while (fgets(line, sizeof(line), manifest) != NULL) { - tok2 = line; - tok1 = strsep(&tok2, "\t"); - if (tok1 == NULL || strcmp(tok1, file) != 0) + p = &line[0]; + span = strcspn(p, "\t") ; + if (span < 1 || strncmp(p, file, span) != 0) continue; /* * We're at the right manifest line. The file count is * in the third element */ - tok1 = strsep(&tok2, "\t"); - tok1 = strsep(&tok2, "\t"); - if (tok1 != NULL) - return atoi(tok1); + span = strcspn(p += span + (*p != '\0' ? 1 : 0), "\t"); + span = strcspn(p += span + (*p != '\0' ? 1 : 0), "\t"); + if (span > 0) { + file_count = (int)strtol(p, (char **)NULL, 10); + if (file_count == 0 && errno == EINVAL) + continue; + return (file_count); + } } } - /* Either we didn't have a manifest, or this archive wasn't there */ - archive = archive_read_new(); + /* + * Either no manifest, or manifest didn't mention this archive. + * Use archive(3) to read the archive, counting files within. + */ + if ((archive = archive_read_new()) == NULL) { + snprintf(errormsg, sizeof(errormsg), + "Error: %s\n", archive_error_string(NULL)); + dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE); + return (-1); + } archive_read_support_format_all(archive); archive_read_support_filter_all(archive); - sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), file); - err = archive_read_open_filename(archive, path, 4096); - if (err != ARCHIVE_OK) { + snprintf(path, sizeof(path), "%s/%s", distdir, file); + retval = archive_read_open_filename(archive, path, 4096); + if (retval != ARCHIVE_OK) { snprintf(errormsg, sizeof(errormsg), "Error while extracting %s: %s\n", file, archive_error_string(archive)); dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE); + archive = NULL; return (-1); } @@ -141,101 +255,75 @@ count_files(const char *file) while (archive_read_next_header(archive, &entry) == ARCHIVE_OK) file_count++; archive_read_free(archive); + archive = NULL; return (file_count); } static int -extract_files(int nfiles, const char **files) +extract_files(struct dpv_file_node *file, int out __unused) { - const char *items[nfiles*2]; - char path[PATH_MAX]; - int archive_files[nfiles]; - int total_files, current_files, archive_file; - struct archive *archive; + int retval; struct archive_entry *entry; - char errormsg[512]; - char status[8]; - int i, err, progress, last_progress; - - err = 0; - progress = 0; - - /* Make the transfer list for dialog */ - for (i = 0; i < nfiles; i++) { - items[i*2] = strrchr(files[i], '/'); - if (items[i*2] != NULL) - items[i*2]++; - else - items[i*2] = files[i]; - items[i*2 + 1] = "Pending"; - } - - dialog_msgbox("", - "Checking distribution archives.\nPlease wait...", 0, 0, FALSE); + char path[PATH_MAX]; + char errormsg[PATH_MAX + 512]; - /* Count all the files */ - total_files = 0; - for (i = 0; i < nfiles; i++) { - archive_files[i] = count_files(files[i]); - if (archive_files[i] < 0) + /* Open the archive if necessary */ + if (archive == NULL) { + if ((archive = archive_read_new()) == NULL) { + snprintf(errormsg, sizeof(errormsg), + "Error: %s\n", archive_error_string(NULL)); + dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE); + dpv_abort = 1; return (-1); - total_files += archive_files[i]; - } - - current_files = 0; - - for (i = 0; i < nfiles; i++) { - archive = archive_read_new(); + } archive_read_support_format_all(archive); archive_read_support_filter_all(archive); - sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), files[i]); - err = archive_read_open_filename(archive, path, 4096); - - items[i*2 + 1] = "In Progress"; - archive_file = 0; - - while ((err = archive_read_next_header(archive, &entry)) == - ARCHIVE_OK) { - last_progress = progress; - progress = (current_files*100)/total_files; - - sprintf(status, "-%d", - (archive_file*100)/archive_files[i]); - items[i*2 + 1] = status; - - if (progress > last_progress) - dialog_mixedgauge("Archive Extraction", - "Extracting distribution files...", 0, 0, - progress, nfiles, - __DECONST(char **, items)); - - err = archive_read_extract(archive, entry, - ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_OWNER | - ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | - ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_FFLAGS); - - if (err != ARCHIVE_OK) - break; - - archive_file++; - current_files++; - } - - items[i*2 + 1] = "Done"; - - if (err != ARCHIVE_EOF) { + snprintf(path, sizeof(path), "%s/%s", distdir, file->path); + retval = archive_read_open_filename(archive, path, 4096); + if (retval != 0) { snprintf(errormsg, sizeof(errormsg), - "Error while extracting %s: %s\n", items[i*2], + "Error opening %s: %s\n", file->name, archive_error_string(archive)); - items[i*2 + 1] = "Failed"; - dialog_msgbox("Extract Error", errormsg, 0, 0, - TRUE); - return (err); + dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE); + file->status = DPV_STATUS_FAILED; + dpv_abort = 1; + return (-1); } + } + /* Read the next archive header */ + retval = archive_read_next_header(archive, &entry); + + /* If that went well, perform the extraction */ + if (retval == ARCHIVE_OK) + retval = archive_read_extract(archive, entry, + ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_OWNER | + ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | + ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_FFLAGS); + + /* Test for either EOF or error */ + if (retval == ARCHIVE_EOF) { archive_read_free(archive); + archive = NULL; + file->status = DPV_STATUS_DONE; + return (100); + } else if (retval != ARCHIVE_OK) { + snprintf(errormsg, sizeof(errormsg), + "Error while extracting %s: %s\n", file->name, + archive_error_string(archive)); + dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE); + file->status = DPV_STATUS_FAILED; + dpv_abort = 1; + return (-1); } - return (0); + dpv_overall_read++; + file->read++; + + /* Calculate [overall] percentage of completion (if possible) */ + if (file->length >= 0) + return (file->read * 100 / file->length); + else + return (-1); } Modified: stable/10/usr.sbin/bsdinstall/distfetch/distfetch.c ============================================================================== --- stable/10/usr.sbin/bsdinstall/distfetch/distfetch.c Mon Jun 1 00:55:15 2015 (r283858) +++ stable/10/usr.sbin/bsdinstall/distfetch/distfetch.c Mon Jun 1 01:06:33 2015 (r283859) @@ -1,5 +1,6 @@ /*- * Copyright (c) 2011 Nathan Whitehorn + * Copyright (c) 2014 Devin Teske <dteske@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,15 +23,21 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + #include <sys/param.h> -#include <stdio.h> +#include <ctype.h> +#include <err.h> +#include <dialog.h> #include <errno.h> #include <fetch.h> -#include <dialog.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> static int fetch_files(int nfiles, char **urls); @@ -39,12 +46,13 @@ main(void) { char *diststring; char **urls; - int i, nfetched, ndists = 0; + int i; + int ndists = 0; + int nfetched; + char error[PATH_MAX + 512]; - if (getenv("DISTRIBUTIONS") == NULL) { - fprintf(stderr, "DISTRIBUTIONS variable is not set\n"); - return (1); - } + if (getenv("DISTRIBUTIONS") == NULL) + errx(EXIT_FAILURE, "DISTRIBUTIONS variable is not set"); diststring = strdup(getenv("DISTRIBUTIONS")); for (i = 0; diststring[i] != 0; i++) @@ -54,9 +62,8 @@ main(void) urls = calloc(ndists, sizeof(const char *)); if (urls == NULL) { - fprintf(stderr, "Out of memory!\n"); free(diststring); - return (1); + errx(EXIT_FAILURE, "Out of memory!"); } init_dialog(stdin, stdout); @@ -65,17 +72,17 @@ main(void) for (i = 0; i < ndists; i++) { urls[i] = malloc(PATH_MAX); - sprintf(urls[i], "%s/%s", getenv("BSDINSTALL_DISTSITE"), - strsep(&diststring, " \t")); + snprintf(urls[i], PATH_MAX, "%s/%s", + getenv("BSDINSTALL_DISTSITE"), strsep(&diststring, " \t")); } if (chdir(getenv("BSDINSTALL_DISTDIR")) != 0) { - char error[512]; - sprintf(error, "Could could change to directory %s: %s\n", + snprintf(error, sizeof(error), + "Could could change to directory %s: %s\n", getenv("BSDINSTALL_DISTDIR"), strerror(errno)); dialog_msgbox("Error", error, 0, 0, TRUE); end_dialog(); - return (1); + return (EXIT_FAILURE); } nfetched = fetch_files(ndists, urls); @@ -87,31 +94,32 @@ main(void) free(urls[i]); free(urls); - return ((nfetched == ndists) ? 0 : 1); + return ((nfetched == ndists) ? EXIT_SUCCESS : EXIT_FAILURE); } static int fetch_files(int nfiles, char **urls) { + FILE *fetch_out; + FILE *file_out; const char **items; - FILE *fetch_out, *file_out; - struct url_stat ustat; - off_t total_bytes, current_bytes, fsize; + int i; + int last_progress; + int nsuccess = 0; /* Number of files successfully downloaded */ + int progress = 0; + size_t chunk; + off_t current_bytes; + off_t fsize; + off_t total_bytes; char status[8]; - char errormsg[512]; + struct url_stat ustat; + char errormsg[PATH_MAX + 512]; uint8_t block[4096]; - size_t chunk; - int i, progress, last_progress; - int nsuccess = 0; /* Number of files successfully downloaded */ - progress = 0; - /* Make the transfer list for dialog */ items = calloc(sizeof(char *), nfiles * 2); - if (items == NULL) { - fprintf(stderr, "Out of memory!\n"); - return (-1); - } + if (items == NULL) + errx(EXIT_FAILURE, "Out of memory!"); for (i = 0; i < nfiles; i++) { items[i*2] = strrchr(urls[i], '/'); @@ -177,7 +185,8 @@ fetch_files(int nfiles, char **urls) } if (ustat.size > 0) { - sprintf(status, "-%jd", (fsize*100)/ustat.size); + snprintf(status, sizeof(status), "-%jd", + (fsize*100)/ustat.size); items[i*2 + 1] = status; } @@ -212,4 +221,3 @@ fetch_files(int nfiles, char **urls) free(items); return (nsuccess); } -
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201506010106.t5116Ypt006992>