/* ----------------------------------------------------------------------- *
 *
 *   Copyright 2008 rPath, 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, Inc., 51 Franklin St, Fifth Floor,
 *   Boston MA 02110-1301, USA; either version 2 of the License, or
 *   (at your option) any later version; incorporated herein by reference.
 *
 * ----------------------------------------------------------------------- */

/*
 * main.c
 *
 * Wrap a Linux image in an ELF (or other) container
 */

#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <sys/mman.h>
#include <sys/types.h>

#include "wraplinux.h"
#include "version.h"

const char *program;

enum longopts {
	OPT_NOLOADHIGH  = 256,
};

const struct option long_options[] = {
	{"params",	 1, 0, 'p'},
	{"cmdline",	 1, 0, 'p'},
	{"commandline",	 1, 0, 'p'},
	{"initrd",	 1, 0, 'i'},
	{"output",	 1, 0, 'o'},
	{"load-high",    0, 0, 'l'},
	{"no-load-high", 0, 0,  OPT_NOLOADHIGH},
	{"elf",		 0, 0, 'E'},
	{"multiboot",	 0, 0, 'M'},
	{"nbi",		 0, 0, 'N'},
	{"help",	 0, 0, 'h'},
	{"version",	 0, 0, 'V'},
	{0, 0, 0, 0}
};

#define OPTSTRING "p:i:o:lEMNhV"

static void usage(int err)
{
	fprintf(stderr,
		"%s %s\n"
		"Usage: %s [options] kernel\n"
		"  --params       -p    kernel commandline parameters\n"
		"  --initrd       -i    initrd (multiple initrd options supported)\n"
		"  --output       -o    output filename (default stdout)\n"
		"  --elf          -E    output in ELF format (default)\n"
		"  --multiboot    -M    output in Multiboot ELF format\n"
		"  --nbi          -N    output in NBI format\n"
		"  --load-high    -l    load entirely above 1 MB\n"
		"                       (default for Multiboot ELF format)\n"
		"  --help         -h    display this help text\n"
		"  --version      -V    print the program version\n",
		WRAPLINUX_PACKAGE, WRAPLINUX_VERSION,
		program);
	exit(err);
}

int main(int argc, char *argv[])
{
	int optch;
	const char *kernel;
	struct string_list *ird = NULL, **irdp = &ird, *ip;
	FILE *out = stdout;
	bool loadhighopt = false;

	program = argv[0];

	opt.output = output_elf;

	while ((optch = getopt_long(argc, argv, OPTSTRING, long_options, NULL))
	       != EOF) {
		switch (optch) {
		case 'p':
			opt.params = optarg;
			break;
		case 'i':
			ip = xmalloc(sizeof *ip);
			ip->str = optarg;
			ip->next = NULL;
			*irdp = ip;
			irdp = &ip->next;
			break;
		case 'o':
			if (optarg[0] == '-' && !optarg[1]) {
				out = stdout;
			} else {
				out = fopen(optarg, "wb");
				if (!out) {
					fprintf(stderr, "%s: %s: %s\n", program,
						optarg, strerror(errno));
					return EX_CANTCREAT;
				}
			}
			break;
		case 'l':
			opt.loadhigh = true;
			loadhighopt  = true;
			break;
		case OPT_NOLOADHIGH:
			opt.loadhigh = false;
			loadhighopt  = true;
			break;
		case 'E':
			opt.output = output_elf;
			break;
		case 'M':
			opt.output = output_multiboot;
			break;
		case 'N':
			opt.output = output_nbi;
			break;
		case 'h':
			usage(0);
			break;
		case 'V':
			printf("%s %s\n", WRAPLINUX_PACKAGE, WRAPLINUX_VERSION);
			exit(0);
		default:
			usage(EX_USAGE);
			break;
		}
	}

	if ((argc - optind) != 1)
		usage(EX_USAGE);

	if (opt.output == output_multiboot && !loadhighopt)
		opt.loadhigh = true;

	kernel = argv[optind];

	if (!opt.params)
		opt.params = "";

	return wrap_kernel(kernel, opt.params, ird, out);
}
