switch-coreboot/util/lar/lar.c
Myles Watson 689dad6eab This patch fixes lar options parsing, a seg fault with long path names, and
makes use of functions that were already defined.  It also adds greedy name
matching for listing and extracting archives, which allows recursive descent
into the lar directory structure.

changes file-by-file:

util/lar/lar.c:
	add more options to the usage message
	use get_larsize() instead of using larsize
	rearrange errors from parsing args to be more correct

util/lar/stream.c:
	change elfname size to MAX_PATHLEN instead of 64
	make file_in_list greedy with filename matches
	change total_size calculation to include file names
	change lar_add_entry to use header_len function instead of reinventing

Signed-off-by: Myles Watson <mylesgw@gmail.com>
Acked-by: Ronald G. Minnich <rminnich@gmail.com>



git-svn-id: svn://coreboot.org/repository/coreboot-v3@632 f3766cd6-281f-0410-b1cd-43a5c92072e9
2008-03-05 14:51:35 +00:00

410 lines
9.4 KiB
C

/*
* lar - lightweight archiver
*
* Copyright (C) 2006-2008 coresystems GmbH
* (Written by Stefan Reinauer <stepan@coresystems.de> for coresystems GmbH)
*
* 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; version 2 of the License.
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "lar.h"
#include "lib.h"
#define VERSION "v0.9.1"
#define COPYRIGHT "Copyright (C) 2006-2008 coresystems GmbH"
static int isverbose = 0;
static int iselfparse = 0;
static long larsize = 0;
static char *bootblock = NULL;
enum compalgo algo = ALGO_NONE;
static void usage(char *name)
{
printf("\nLAR - the Lightweight Archiver " VERSION "\n" COPYRIGHT "\n\n");
printf("Usage: %s [-ecxal] archive.lar [-b NAME] [-s SIZE[M|k]]\n",name);
printf("\t[[[file1] file2] ...]\n\n");
printf("Examples:\n");
printf(" lar -c -s 32k -b bootblock myrom.lar foo nocompress:bar\n");
printf(" lar -a myrom.lar foo blob:baz\n");
printf(" lar -l myrom.lar\n\n");
printf("File names:\n");
printf(" Names specified in the create or add modes are formatted as\n");
printf(" follows: [flags]:[filename]:[pathname].\n");
printf(" * Flags are modifiers for the file. Valid flags:\n");
printf(" nocompress\tDon't compress the file in the LAR\n");
printf(" * Filename is the name of the file on disk. If no pathname\n");
printf(" is specified, then the filename will also be the path name\n");
printf(" used in the LAR.\n");
printf(" * Pathname is the name to use in the LAR header.\n\n");
printf("Create options:\n");
printf(" -s [size] \tSpecify the size of the archive.\n");
printf(" \tUse a 'k' suffix to multiply the size by 1024 or\n");
printf(" \ta 'm' suffix to multiple the size by 1024*1024.\n");
printf(" -b [bootblock]\tSpecify the bootblock blob\n");
printf(" -C [lzma|nrv2b]\tSpecify the compression method to use\n\n");
printf(" -e pre-parse the payload ELF into LAR segments. Recommended\n\n");
printf("General options\n");
printf(" -v\tEnable verbose mode\n");
printf(" -V\tShow the version\n");
printf(" -h\tShow this help\n");
printf("\n");
}
int elfparse(void)
{
return iselfparse;
}
/* Add a human touch to the LAR size by allowing suffixes:
* XX[KkMm] where k = XX * 1024 and m or M = xx * 1024 * 1024
*/
static void parse_larsize(char *str)
{
char *p = NULL;
unsigned int size = strtoul(str, &p, 0);
if (p != NULL) {
if (*p == 'k' || *p == 'K')
size *= 1024;
else if (*p == 'm' || *p == 'M')
size *= (1024 * 1024);
else if (*p) {
fprintf(stderr, "Unknown LAR size suffix '%c'\n", *p);
exit(1);
}
}
larsize = size;
}
int verbose(void)
{
return isverbose;
}
long get_larsize(void)
{
return larsize;
}
char *get_bootblock(void)
{
return bootblock;
}
int create_lar(const char *archivename, struct file *files)
{
struct lar *lar = lar_new_archive(archivename, get_larsize());
if (lar == NULL) {
fprintf(stderr, "Unable to create %s as a LAR archive.\n",
archivename);
exit(1);
}
for( ; files; files = files->next) {
if (lar_add_file(lar, files)) {
fprintf(stderr, "Error adding %s:%s (%d) to the LAR.\n",
files->name, files->pathname, files->algo);
lar_close_archive(lar);
exit(1);
}
}
if (lar_add_bootblock(lar, bootblock)) {
fprintf(stderr, "Error adding the bootblock to the LAR.\n");
lar_close_archive(lar);
exit(1);
}
lar_close_archive(lar);
return 0;
}
int add_lar(const char *archivename, struct file *files)
{
struct lar *lar = lar_open_archive(archivename);
if (lar == NULL) {
fprintf(stderr, "Unable to open LAR archive %s\n", archivename);
exit(1);
}
for( ; files; files = files->next) {
if (lar_add_file(lar, files)) {
fprintf(stderr, "Error adding %s:%s (%d) to the LAR.\n",
files->name, files->pathname, files->algo);
lar_close_archive(lar);
exit(1);
}
}
lar_close_archive(lar);
return 0;
}
int list_lar(const char *archivename, struct file *files)
{
struct lar *lar = lar_open_archive(archivename);
if (lar == NULL) {
fprintf(stderr, "Unable to open LAR archive %s\n", archivename);
exit(1);
}
lar_list_files(lar, files);
lar_close_archive(lar);
return 0;
}
int zerofill_lar(const char *archivename)
{
struct lar_header *header;
int ret, hlen;
int pathlen;
u32 *walk, csum;
u32 offset;
char *name = "zerofill";
int zerolen;
char *zero;
struct lar *lar = lar_open_archive(archivename);
if (lar == NULL) {
fprintf(stderr, "Unable to open LAR archive %s\n", archivename);
exit(1);
}
zerolen = maxsize(lar, name);
if (zerolen <= 0) {
fprintf(stderr, "No room for zerofill.\n");
return -1;
}
zero = malloc(zerolen);
memset(zero, 0xff, zerolen);
lar_add_entry(lar, name, zero, zerolen, zerolen,0, 0, 0);
lar_close_archive(lar);
return 0;
}
int extract_lar(const char *archivename, struct file *files)
{
int ret;
struct lar *lar = lar_open_archive(archivename);
if (lar == NULL) {
fprintf(stderr, "Unable to open LAR archive %s\n", archivename);
exit(1);
}
ret = lar_extract_files(lar, files);
lar_close_archive(lar);
return ret;
}
int main(int argc, char *argv[])
{
int opt;
int option_index = 0;
int larmode = NONE;
char *archivename = NULL;
static struct option long_options[] = {
{"add", 0, 0, 'a'},
{"create", 0, 0, 'c'},
{"compress-algo", 1, 0, 'C'},
{"extract", 0, 0, 'x'},
{"list", 0, 0, 'l'},
{"size", 1, 0, 's'},
{"bootblock", 1, 0, 'b'},
{"elfparse", 1, 0, 'e'},
{"verbose", 0, 0, 'v'},
{"version", 0, 0, 'V'},
{"zerofill", 0, 0, 'z'},
{"help", 0, 0, 'h'},
{0, 0, 0, 0}
};
if (argc < 3) {
usage(argv[0]);
exit(1);
}
while ((opt = getopt_long(argc, argv, "acC:xzels:b:vVh?",
long_options, &option_index)) != EOF) {
switch (opt) {
case 'a':
larmode = ADD;
break;
case 'c':
larmode = CREATE;
break;
case 'C':
if (strcasecmp("lzma", optarg) == 0) {
algo = ALGO_LZMA;
}
if (strcasecmp("nrv2b", optarg) == 0) {
algo = ALGO_NRV2B;
}
break;
case 'l':
larmode = LIST;
break;
case 'e':
iselfparse = 1;
break;
case 'x':
larmode = EXTRACT;
break;
case 'z':
larmode = ZEROFILL;
break;
case 's':
parse_larsize(optarg);
break;
case 'b':
bootblock = strdup(optarg);
if (!bootblock) {
fprintf(stderr, "Out of memory.\n");
exit(1);
}
break;
case 'v':
isverbose = 1;
break;
case 'V':
printf("LAR - the Lightweight Archiver " VERSION "\n");
break;
default:
usage(argv[0]);
exit(1);
}
}
// tar compatibility: Allow lar x as alternative to
// lar -x. This should be dropped or done correctly.
// Right now, you'd have to write lar x -v instead of
// lar xv... but the author of this software was too
// lazy to handle all option parameter twice.
if (larmode == NONE && optind < argc) {
if (strncmp(argv[optind], "x", 2) == 0)
larmode = EXTRACT;
else if (strncmp(argv[optind], "c", 2) == 0)
larmode = CREATE;
else if (strncmp(argv[optind], "l", 2) == 0)
larmode = LIST;
else if (strncmp(argv[optind], "z", 2) == 0)
larmode = ZEROFILL;
/* If larmode changed in this if branch,
* eat a parameter
*/
if (larmode != NONE)
optind++;
}
if (larmode == NONE) {
usage(argv[0]);
fprintf(stderr, "Error: No mode specified.\n\n");
exit(1);
}
/* size only makes sense when creating a lar */
if (larmode != CREATE && get_larsize()) {
printf("Warning: size parameter ignored since "
"not creating an archive.\n");
}
if (larmode == CREATE && !get_larsize()) {
printf("When creating a LAR archive, "
"you must specify an archive size.\n");
exit(1);
}
/* adding a bootblock only makes sense when creating a lar */
if (bootblock && larmode != CREATE) {
printf("Warning: bootblock parameter ignored since "
"not creating an archive.\n");
}
if (optind < argc) {
archivename = argv[optind++];
} else if (larmode != ZEROFILL) {
usage(argv[0]);
fprintf(stderr, "Error: No archive name.\n\n");
exit(1);
}
/* when a new archive is created or added to, recurse over
* the physical files when a directory is found.
* Otherwise just add the directory to the match list
*/
while (optind < argc) {
if (larmode == CREATE || larmode == ADD) {
char *name=argv[optind++], *filename, *pathname;
enum compalgo file_algo=algo;
if (lar_process_name(name, &filename,
&pathname, &file_algo))
exit(1);
add_files(filename,pathname, file_algo);
} else
add_file_or_directory(argv[optind++]);
}
switch (larmode) {
case ADD:
add_lar(archivename, get_files());
break;
case EXTRACT:
extract_lar(archivename, get_files());
break;
case CREATE:
create_lar(archivename, get_files());
break;
case LIST:
list_lar(archivename, get_files());
break;
case ZEROFILL:
zerofill_lar(archivename);
break;
}
free_files();
return 0;
}