1330449Seadler/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
448905Srnordier * Copyright (c) 1999 Global Technology Associates, Inc.
548905Srnordier * All rights reserved.
648905Srnordier *
748905Srnordier * Redistribution and use in source and binary forms, with or without
848905Srnordier * modification, are permitted provided that the following conditions
948905Srnordier * are met:
1048905Srnordier * 1. Redistributions of source code must retain the above copyright
1148905Srnordier *    notice, this list of conditions and the following disclaimer.
1248905Srnordier * 2. Redistributions in binary form must reproduce the above copyright
1348905Srnordier *    notice, this list of conditions and the following disclaimer in the
1448905Srnordier *    documentation and/or other materials provided with the distribution.
1548905Srnordier *
1648905Srnordier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND
1748905Srnordier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1848905Srnordier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1948905Srnordier * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
2048905Srnordier * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
2148905Srnordier * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
2248905Srnordier * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
2348905Srnordier * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2448905Srnordier * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
2548905Srnordier * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
2648905Srnordier * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2748905Srnordier */
2848905Srnordier
2948905Srnordier#ifndef lint
3048905Srnordierstatic const char rcsid[] =
3150479Speter  "$FreeBSD: stable/11/usr.sbin/kgzip/kgzip.c 330449 2018-03-05 07:26:05Z eadler $";
3248905Srnordier#endif /* not lint */
3348905Srnordier
3448905Srnordier#include <sys/types.h>
3548905Srnordier#include <err.h>
3664214Skris#include <paths.h>
3748905Srnordier#include <stdio.h>
3848905Srnordier#include <stdlib.h>
3948905Srnordier#include <string.h>
4048905Srnordier#include <unistd.h>
4148905Srnordier
4248905Srnordier#include "kgzip.h"
4348905Srnordier
4448905Srnordier#define FN_SRC		0	/* Filename: source */
4548905Srnordier#define FN_OBJ		1	/* Filename: relocatable */
4648905Srnordier#define FN_KGZ		2	/* Filename: executable */
4748905Srnordier#define FN_CNT		3	/* Number of filenames */
4848905Srnordier
4948905Srnordier#define SFX_OBJ 	".o"	/* Filename suffix: relocatable */
5048905Srnordier#define SFX_KGZ 	".kgz"	/* Filename suffix: executable */
5148905Srnordier#define SFX_MAX 	5	/* Size of larger filename suffix */
5248905Srnordier
5348905Srnordierconst char *loader = "/usr/lib/kgzldr.o";  /* Default loader */
5468313Srnordierint format;			/* Output format */
5548905Srnordier
5656128Skrischar *tname;			/* Name of temporary file */
5748905Srnordier
5848905Srnordierstatic void cleanup(void);
5948905Srnordierstatic void mk_fn(int, const char *, const char *, char *[]);
6048905Srnordierstatic void usage(void);
6148905Srnordier
6248905Srnordier/*
6348905Srnordier * Compress a kernel.
6448905Srnordier */
6548905Srnordierint
6648905Srnordiermain(int argc, char *argv[])
6748905Srnordier{
6848905Srnordier    static char *fn[FN_CNT];
6948905Srnordier    struct kgz_hdr kh;
7048905Srnordier    const char *output;
7164214Skris    char *tmpdir;
7248905Srnordier    int cflag, vflag, c;
7348905Srnordier
7464214Skris    tmpdir = getenv("TMPDIR");
7568966Srnordier    if (asprintf(&tname, "%s/kgzXXXXXXXXXX",
7668966Srnordier		 tmpdir == NULL ? _PATH_TMP : tmpdir) == -1)
7768313Srnordier	errx(1, "Out of memory");
7848905Srnordier    output = NULL;
7948905Srnordier    cflag = vflag = 0;
8068313Srnordier    while ((c = getopt(argc, argv, "cvf:l:o:")) != -1)
8148905Srnordier	switch (c) {
8248905Srnordier	case 'c':
8348905Srnordier	    cflag = 1;
8448905Srnordier	    break;
8548905Srnordier	case 'v':
8648905Srnordier	    vflag = 1;
8748905Srnordier	    break;
8868313Srnordier	case 'f':
8968313Srnordier	    if (!strcmp(optarg, "aout"))
9068313Srnordier		format = F_AOUT;
9168313Srnordier	    else if (!strcmp(optarg, "elf"))
9268313Srnordier		format = F_ELF;
9368313Srnordier	    else
9468313Srnordier		errx(1, "%s: Unknown format", optarg);
9568313Srnordier	    break;
9648905Srnordier	case 'l':
9748905Srnordier	    loader = optarg;
9848905Srnordier	    break;
9948905Srnordier	case 'o':
10048905Srnordier	    output = optarg;
10148905Srnordier	    break;
10248905Srnordier	default:
10348905Srnordier	    usage();
10448905Srnordier	}
10548905Srnordier    argc -= optind;
10648905Srnordier    argv += optind;
10748905Srnordier    if (argc != 1)
10848905Srnordier	usage();
10948905Srnordier    atexit(cleanup);
11048905Srnordier    mk_fn(cflag, *argv, output, fn);
11148905Srnordier    memset(&kh, 0, sizeof(kh));
11268313Srnordier    if (fn[FN_SRC]) {
11368313Srnordier	if (!format)
11468313Srnordier	    format = F_ELF;
11548905Srnordier	kgzcmp(&kh, fn[FN_SRC], fn[FN_OBJ]);
11668313Srnordier    }
11748905Srnordier    if (!cflag)
11848905Srnordier	kgzld(&kh, fn[FN_OBJ], fn[FN_KGZ]);
11948905Srnordier    if (vflag)
12048905Srnordier	printf("dload=%#x dsize=%#x isize=%#x entry=%#x nsize=%#x\n",
12148905Srnordier	       kh.dload, kh.dsize, kh.isize, kh.entry, kh.nsize);
12248905Srnordier    return 0;
12348905Srnordier}
12448905Srnordier
12548905Srnordier/*
12648905Srnordier * Clean up after processing.
12748905Srnordier */
12848905Srnordierstatic void
12948905Srnordiercleanup(void)
13048905Srnordier{
13148905Srnordier    if (tname)
13248905Srnordier	unlink(tname);
13348905Srnordier}
13448905Srnordier
13548905Srnordier/*
13648905Srnordier * Make the required filenames.
13748905Srnordier */
13848905Srnordierstatic void
13948905Srnordiermk_fn(int cflag, const char *f1, const char *f2, char *fn[])
14048905Srnordier{
14148905Srnordier    const char *p, *s;
14248905Srnordier    size_t n;
14356128Skris    int i, fd;
14448905Srnordier
14548905Srnordier    i = 0;
14648905Srnordier    s = strrchr(f1, 0);
14748905Srnordier    n = sizeof(SFX_OBJ) - 1;
14848905Srnordier    if ((size_t)(s - f1) > n && !memcmp(s - n, SFX_OBJ, n)) {
14948905Srnordier	s -= n;
15048905Srnordier	i++;
15148905Srnordier    }
15248905Srnordier    fn[i++] = (char *)f1;
15348905Srnordier    if (i == FN_OBJ && !cflag) {
15456128Skris	if ((fd = mkstemp(tname)) == -1)
15548905Srnordier	    err(1, NULL);
15656128Skris	close(fd);
157116222Sobrien	fn[i++] = tname;
15848905Srnordier    }
15948905Srnordier    if (!(fn[i] = (char *)f2)) {
16048905Srnordier	p = (p = strrchr(f1, '/')) ? p + 1 : f1;
16148905Srnordier	n = (size_t)(s - p);
16248905Srnordier	if (!(fn[i] = malloc(n + SFX_MAX)))
16348905Srnordier	    err(1, NULL);
16448905Srnordier	memcpy(fn[i], p, n);
16548905Srnordier	strcpy(fn[i] + n, i == FN_OBJ ? SFX_OBJ : SFX_KGZ);
16648905Srnordier    }
16748905Srnordier}
16848905Srnordier
16948905Srnordier/*
17048905Srnordier * Display usage information.
17148905Srnordier */
17248905Srnordierstatic void
17348905Srnordierusage(void)
17448905Srnordier{
17548905Srnordier    fprintf(stderr,
176112048Sru      "usage: kgzip [-cv] [-f format] [-l loader] [-o output] file\n");
17748905Srnordier    exit(1);
17848905Srnordier}
179