Optimize program flow for execution speed. Also fix some more style(9) nits

while here:
+ Fix an issue when extracting small archives where dialog_mixedgauge was
  not rendering; leaving the user wondering if anything happened.
+ Add #ifdef's to assuage compilation against older libarchive
  NB: Minimize diff between branches; make merging easier.
+ Add missing calls to end_dialog(3)
+ Change string processing from strtok(3) to strcspn(3) (O(1) optimization)
+ Use EXIT_SUCCESS and EXIT_FAILURE instead of 0/1
+ Optimize getenv(3) use, using stored results instead of calling repeatedly
  NB: Fixes copy/paste error wherein we display getenv(BSDINSTALL_DISTDIR) in
      an error msgbox when chdir(2) to getenv(BSDINSTALL_CHROOT) fails
      (wrong variable displayed in msgbox).
+ Use strtol(3) instead of [deprecated] atoi(3)
+ Add additional error checking (e.g., check return of archive_read_new(3))
+ Assign DECONST strings to static variables
+ Fix typo in distextract.c error message (s/Could could/Could not/)
+ Add comments and make a minor whitespace adjustment

Reviewed by:	nwhitehorn, julian
This commit is contained in:
dteske 2014-10-01 18:59:57 +00:00
parent 77fb3d6bbe
commit b1da57a21d
2 changed files with 154 additions and 68 deletions

View File

@ -40,45 +40,102 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
/* Data to process */
static char *distdir = NULL;
struct file_node {
char *path;
char *name;
int length;
struct file_node *next;
};
static struct file_node *dists = NULL;
/* Function prototypes */
static int count_files(const char *file);
static int extract_files(int nfiles, const char **files);
static int extract_files(int nfiles, struct file_node *files);
#if __FreeBSD_version <= 1000008 /* r232154: bump for libarchive update */
#define archive_read_support_filter_all(x) \
archive_read_support_compression_all(x)
#endif
#define _errx(...) (end_dialog(), errx(__VA_ARGS__))
int
main(void)
{
const char **dists;
char *diststring;
int i;
char *chrootdir;
char *distributions;
int ndists = 0;
int retval;
size_t file_node_size = sizeof(struct file_node);
size_t span;
struct file_node *dist = dists;
char error[PATH_MAX + 512];
if (getenv("DISTRIBUTIONS") == NULL)
if ((distributions = getenv("DISTRIBUTIONS")) == NULL)
errx(EXIT_FAILURE, "DISTRIBUTIONS variable is not set");
if ((distdir = getenv("BSDINSTALL_DISTDIR")) == NULL)
distdir = __DECONST(char *, "");
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) {
free(diststring);
errx(EXIT_FAILURE, "Out of memory!");
}
for (i = 0; i < ndists; i++)
dists[i] = strsep(&diststring, " \t");
/* Initialize dialog(3) */
init_dialog(stdin, stdout);
dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer");
dlg_put_backtitle();
if (chdir(getenv("BSDINSTALL_CHROOT")) != 0) {
dialog_msgbox("",
"Checking distribution archives.\nPlease wait...", 4, 35, FALSE);
/*
* Parse $DISTRIBUTIONS into linked-list
*/
while (*distributions != '\0') {
span = strcspn(distributions, "\t\n\v\f\r ");
if (span < 1) { /* currently on whitespace */
distributions++;
continue;
}
ndists++;
/* 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 could change to directory %s: %s\n",
getenv("BSDINSTALL_DISTDIR"), strerror(errno));
"Could not change to directory %s: %s\n",
chrootdir, strerror(errno));
dialog_msgbox("Error", error, 0, 0, TRUE);
end_dialog();
return (EXIT_FAILURE);
@ -88,20 +145,28 @@ main(void)
end_dialog();
free(diststring);
free(dists);
while ((dist = dists) != NULL) {
dists = dist->next;
if (dist->path != NULL)
free(dist->path);
free(dist);
}
return (retval);
}
/*
* 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)
{
static FILE *manifest = NULL;
char *tok1;
char *tok2;
char *p;
int file_count;
int retval;
size_t span;
struct archive *archive;
struct archive_entry *entry;
char line[512];
@ -109,36 +174,46 @@ count_files(const char *file)
char errormsg[PATH_MAX + 512];
if (manifest == NULL) {
snprintf(path, sizeof(path), "%s/MANIFEST",
getenv("BSDINSTALL_DISTDIR"));
snprintf(path, sizeof(path), "%s/MANIFEST", distdir);
manifest = fopen(path, "r");
}
if (manifest != NULL) {
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);
snprintf(path, sizeof(path), "%s/%s", getenv("BSDINSTALL_DISTDIR"),
file);
snprintf(path, sizeof(path), "%s/%s", distdir, file);
retval = archive_read_open_filename(archive, path, 4096);
if (retval != ARCHIVE_OK) {
snprintf(errormsg, sizeof(errormsg),
@ -157,7 +232,7 @@ count_files(const char *file)
}
static int
extract_files(int nfiles, const char **files)
extract_files(int nfiles, struct file_node *files)
{
int archive_file;
int archive_files[nfiles];
@ -169,43 +244,51 @@ extract_files(int nfiles, const char **files)
int total_files = 0;
struct archive *archive;
struct archive_entry *entry;
struct file_node *file;
char status[8];
static char title[] = "Archive Extraction";
static char pprompt[] = "Extracting distribution files...\n";
char path[PATH_MAX];
char errormsg[PATH_MAX + 512];
const char *items[nfiles*2];
/* 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];
i = 0;
for (file = files; file != NULL; file = file->next) {
items[i*2] = file->name;
items[i*2 + 1] = "Pending";
archive_files[i] = file->length;
total_files += file->length;
i++;
}
dialog_msgbox("",
"Checking distribution archives.\nPlease wait...", 0, 0, FALSE);
/* Count all the files */
for (i = 0; i < nfiles; i++) {
archive_files[i] = count_files(files[i]);
if (archive_files[i] < 0)
return (-1);
total_files += archive_files[i];
}
for (i = 0; i < nfiles; i++) {
archive = archive_read_new();
i = 0;
for (file = files; file != NULL; file = file->next) {
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 (EXIT_FAILURE);
}
archive_read_support_format_all(archive);
archive_read_support_filter_all(archive);
snprintf(path, sizeof(path), "%s/%s",
getenv("BSDINSTALL_DISTDIR"), files[i]);
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 opening %s: %s\n", file->name,
archive_error_string(archive));
dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE);
return (EXIT_FAILURE);
}
items[i*2 + 1] = "In Progress";
archive_file = 0;
dialog_mixedgauge(title, pprompt, 0, 0, progress, nfiles,
__DECONST(char **, items));
while ((retval = archive_read_next_header(archive, &entry)) ==
ARCHIVE_OK) {
last_progress = progress;
@ -216,8 +299,7 @@ extract_files(int nfiles, const char **files)
items[i*2 + 1] = status;
if (progress > last_progress)
dialog_mixedgauge("Archive Extraction",
"Extracting distribution files...", 0, 0,
dialog_mixedgauge(title, pprompt, 0, 0,
progress, nfiles,
__DECONST(char **, items));
@ -240,12 +322,16 @@ extract_files(int nfiles, const char **files)
"Error while extracting %s: %s\n", items[i*2],
archive_error_string(archive));
items[i*2 + 1] = "Failed";
dialog_msgbox("Extract Error", errormsg, 0, 0,
TRUE);
dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE);
return (retval);
}
progress = (current_files*100)/total_files;
dialog_mixedgauge(title, pprompt, 0, 0, progress, nfiles,
__DECONST(char **, items));
archive_read_free(archive);
i++;
}
return (EXIT_SUCCESS);

View File

@ -82,7 +82,7 @@ main(void)
getenv("BSDINSTALL_DISTDIR"), strerror(errno));
dialog_msgbox("Error", error, 0, 0, TRUE);
end_dialog();
return (1);
return (EXIT_FAILURE);
}
nfetched = fetch_files(ndists, urls);
@ -94,7 +94,7 @@ main(void)
free(urls[i]);
free(urls);
return ((nfetched == ndists) ? 0 : 1);
return ((nfetched == ndists) ? EXIT_SUCCESS : EXIT_FAILURE);
}
static int