1de566360SJordan K. Hubbard /* 2de566360SJordan K. Hubbard * Copyright (c) 1994 University of Maryland 3de566360SJordan K. Hubbard * All Rights Reserved. 4de566360SJordan K. Hubbard * 5de566360SJordan K. Hubbard * Permission to use, copy, modify, distribute, and sell this software and its 6de566360SJordan K. Hubbard * documentation for any purpose is hereby granted without fee, provided that 7de566360SJordan K. Hubbard * the above copyright notice appear in all copies and that both that 8de566360SJordan K. Hubbard * copyright notice and this permission notice appear in supporting 9de566360SJordan K. Hubbard * documentation, and that the name of U.M. not be used in advertising or 10de566360SJordan K. Hubbard * publicity pertaining to distribution of the software without specific, 11de566360SJordan K. Hubbard * written prior permission. U.M. makes no representations about the 12de566360SJordan K. Hubbard * suitability of this software for any purpose. It is provided "as is" 13de566360SJordan K. Hubbard * without express or implied warranty. 14de566360SJordan K. Hubbard * 15de566360SJordan K. Hubbard * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 16de566360SJordan K. Hubbard * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. 17de566360SJordan K. Hubbard * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18de566360SJordan K. Hubbard * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 19de566360SJordan K. Hubbard * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 20de566360SJordan K. Hubbard * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21de566360SJordan K. Hubbard * 22de566360SJordan K. Hubbard * Author: James da Silva, Systems Design and Analysis Group 23de566360SJordan K. Hubbard * Computer Science Department 24de566360SJordan K. Hubbard * University of Maryland at College Park 25de566360SJordan K. Hubbard */ 2650e525e4SAlex Richardson /*- 2750e525e4SAlex Richardson * SPDX-License-Identifier: BSD-2-Clause 2850e525e4SAlex Richardson * 2950e525e4SAlex Richardson * Copyright 2020 Alex Richardson <arichardson@FreeBSD.org> 3050e525e4SAlex Richardson * 3150e525e4SAlex Richardson * This software was developed by SRI International and the University of 3250e525e4SAlex Richardson * Cambridge Computer Laboratory (Department of Computer Science and 3350e525e4SAlex Richardson * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the 3450e525e4SAlex Richardson * DARPA SSITH research programme. 3550e525e4SAlex Richardson * 3650e525e4SAlex Richardson * Redistribution and use in source and binary forms, with or without 3750e525e4SAlex Richardson * modification, are permitted provided that the following conditions 3850e525e4SAlex Richardson * are met: 3950e525e4SAlex Richardson * 1. Redistributions of source code must retain the above copyright 4050e525e4SAlex Richardson * notice, this list of conditions and the following disclaimer. 4150e525e4SAlex Richardson * 2. Redistributions in binary form must reproduce the above copyright 4250e525e4SAlex Richardson * notice, this list of conditions and the following disclaimer in the 4350e525e4SAlex Richardson * documentation and/or other materials provided with the distribution. 4450e525e4SAlex Richardson * 4550e525e4SAlex Richardson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 4650e525e4SAlex Richardson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4750e525e4SAlex Richardson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4850e525e4SAlex Richardson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4950e525e4SAlex Richardson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5050e525e4SAlex Richardson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5150e525e4SAlex Richardson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5250e525e4SAlex Richardson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5350e525e4SAlex Richardson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5450e525e4SAlex Richardson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5550e525e4SAlex Richardson * SUCH DAMAGE. 5650e525e4SAlex Richardson * 5750e525e4SAlex Richardson */ 58de566360SJordan K. Hubbard /* 59de566360SJordan K. Hubbard * crunched_main.c - main program for crunched binaries, it branches to a 60de566360SJordan K. Hubbard * particular subprogram based on the value of argv[0]. Also included 61de566360SJordan K. Hubbard * is a little program invoked when the crunched binary is called via 62de566360SJordan K. Hubbard * its EXECNAME. This one prints out the list of compiled-in binaries, 63de566360SJordan K. Hubbard * or calls one of them based on argv[1]. This allows the testing of 64de566360SJordan K. Hubbard * the crunched binary without creating all the links. 65de566360SJordan K. Hubbard */ 6602c75192SDavid E. O'Brien 6750e525e4SAlex Richardson #include <sys/param.h> 6850e525e4SAlex Richardson #include <sys/auxv.h> 6950e525e4SAlex Richardson #include <sys/sysctl.h> 7050e525e4SAlex Richardson 7150e525e4SAlex Richardson #include <err.h> 72de566360SJordan K. Hubbard #include <stdio.h> 735e8bbdf1SYaroslav Tykhiy #include <stdlib.h> 74de566360SJordan K. Hubbard #include <string.h> 75de566360SJordan K. Hubbard 76fc905210SKyle Evans typedef int crunched_stub_t(int, char **, char **); 77fc905210SKyle Evans 78de566360SJordan K. Hubbard struct stub { 79fc905210SKyle Evans const char *name; 80fc905210SKyle Evans crunched_stub_t *f; 81de566360SJordan K. Hubbard }; 82de566360SJordan K. Hubbard 8350e525e4SAlex Richardson extern const char *__progname; 84de566360SJordan K. Hubbard extern struct stub entry_points[]; 85*f122045eSMartin Tournoij extern int num_entry_points; 86de566360SJordan K. Hubbard 87*f122045eSMartin Tournoij static void crunched_usage(int); 88e881ec16SRyan Libby 89fc905210SKyle Evans crunched_stub_t crunched_main; 90*f122045eSMartin Tournoij crunched_stub_t crunched_list; 91fc905210SKyle Evans 9250e525e4SAlex Richardson static struct stub * 9350e525e4SAlex Richardson find_entry_point(const char *basename) 94de566360SJordan K. Hubbard { 95*f122045eSMartin Tournoij for (int i = 0; i < num_entry_points; i++) { 96*f122045eSMartin Tournoij struct stub *ep = &entry_points[i]; 97b0f558dfSAlex Richardson if (!strcmp(basename, ep->name)) 9850e525e4SAlex Richardson return (ep); 99*f122045eSMartin Tournoij } 100f7ff7baaSAlex Richardson return (NULL); 10150e525e4SAlex Richardson } 10250e525e4SAlex Richardson 10350e525e4SAlex Richardson static const char * 10450e525e4SAlex Richardson get_basename(const char *exe_path) 10550e525e4SAlex Richardson { 10650e525e4SAlex Richardson const char *slash = strrchr(exe_path, '/'); 10750e525e4SAlex Richardson return (slash ? slash + 1 : exe_path); 10850e525e4SAlex Richardson } 10950e525e4SAlex Richardson 11050e525e4SAlex Richardson int 11150e525e4SAlex Richardson main(int argc, char **argv, char **envp) 11250e525e4SAlex Richardson { 11350e525e4SAlex Richardson struct stub *ep = NULL; 11450e525e4SAlex Richardson const char *basename = NULL; 1157483b9e4SStefan Eßer char buf[MAXPATHLEN]; 11650e525e4SAlex Richardson 11750e525e4SAlex Richardson /* 11850e525e4SAlex Richardson * Look at __progname first (this will be set if the crunched binary is 11950e525e4SAlex Richardson * invoked directly). 12050e525e4SAlex Richardson */ 12150e525e4SAlex Richardson if (__progname) { 12250e525e4SAlex Richardson basename = get_basename(__progname); 12350e525e4SAlex Richardson ep = find_entry_point(basename); 12450e525e4SAlex Richardson } 12550e525e4SAlex Richardson 12650e525e4SAlex Richardson /* 12750e525e4SAlex Richardson * Otherwise try to find entry point based on argv[0] (this works for 12850e525e4SAlex Richardson * both symlinks as well as hardlinks). However, it does not work when 12950e525e4SAlex Richardson * su invokes a crunched shell because it sets argv[0] to _su when 13050e525e4SAlex Richardson * invoking the shell. In that case we look at AT_EXECPATH as a 13150e525e4SAlex Richardson * fallback. 13250e525e4SAlex Richardson */ 13350e525e4SAlex Richardson if (ep == NULL) { 13450e525e4SAlex Richardson basename = get_basename(argv[0]); 13550e525e4SAlex Richardson ep = find_entry_point(basename); 13650e525e4SAlex Richardson } 13750e525e4SAlex Richardson 13850e525e4SAlex Richardson /* 13950e525e4SAlex Richardson * If we didn't find the entry point based on __progname or argv[0], 14050e525e4SAlex Richardson * try AT_EXECPATH to get the actual binary that was executed. 14150e525e4SAlex Richardson */ 14250e525e4SAlex Richardson if (ep == NULL) { 14350e525e4SAlex Richardson int error = elf_aux_info(AT_EXECPATH, &buf, sizeof(buf)); 14450e525e4SAlex Richardson 14550e525e4SAlex Richardson if (error == 0) { 14650e525e4SAlex Richardson const char *exe_name = get_basename(buf); 14750e525e4SAlex Richardson /* 14850e525e4SAlex Richardson * Keep using argv[0] if AT_EXECPATH is the crunched 14950e525e4SAlex Richardson * binary so that symlinks to the crunched binary report 15050e525e4SAlex Richardson * "not compiled in" instead of invoking 15150e525e4SAlex Richardson * crunched_main(). 15250e525e4SAlex Richardson */ 15350e525e4SAlex Richardson if (strcmp(exe_name, EXECNAME) != 0) { 15450e525e4SAlex Richardson basename = exe_name; 15550e525e4SAlex Richardson ep = find_entry_point(basename); 15650e525e4SAlex Richardson } 15750e525e4SAlex Richardson } else { 15850e525e4SAlex Richardson warnc(error, "elf_aux_info(AT_EXECPATH) failed"); 15950e525e4SAlex Richardson } 16050e525e4SAlex Richardson } 16150e525e4SAlex Richardson 16250e525e4SAlex Richardson if (basename == NULL || *basename == '\0') 163*f122045eSMartin Tournoij crunched_usage(1); 16450e525e4SAlex Richardson 16550e525e4SAlex Richardson if (ep != NULL) { 1668f3548b2SGregory Neil Shapiro return ep->f(argc, argv, envp); 16750e525e4SAlex Richardson } else { 168*f122045eSMartin Tournoij fprintf(stderr, "%s: %s not compiled in\n\n", 169*f122045eSMartin Tournoij EXECNAME, basename); 170*f122045eSMartin Tournoij crunched_usage(1); 171de566360SJordan K. Hubbard } 172de566360SJordan K. Hubbard } 173de566360SJordan K. Hubbard 17402c75192SDavid E. O'Brien int 17502c75192SDavid E. O'Brien crunched_main(int argc, char **argv, char **envp) 176de566360SJordan K. Hubbard { 177de566360SJordan K. Hubbard if (argc <= 1) 178*f122045eSMartin Tournoij crunched_usage(0); 179de566360SJordan K. Hubbard 18050e525e4SAlex Richardson __progname = get_basename(argv[1]); 181b0c70f81SGregory Neil Shapiro return main(--argc, ++argv, envp); 182de566360SJordan K. Hubbard } 183de566360SJordan K. Hubbard 184*f122045eSMartin Tournoij int 185*f122045eSMartin Tournoij crunched_list(int argc __unused, char **argv __unused, char **envp __unused) 186*f122045eSMartin Tournoij { 187*f122045eSMartin Tournoij for (int i = 0; i < num_entry_points - 2; i++) 188*f122045eSMartin Tournoij printf("%s\n", entry_points[i].name); 189*f122045eSMartin Tournoij return (0); 190*f122045eSMartin Tournoij } 191*f122045eSMartin Tournoij 192e881ec16SRyan Libby static void 193*f122045eSMartin Tournoij crunched_usage(int code) 194de566360SJordan K. Hubbard { 195de566360SJordan K. Hubbard int columns, len; 196*f122045eSMartin Tournoij FILE *out = stdout; 197*f122045eSMartin Tournoij if (code > 0) 198*f122045eSMartin Tournoij out = stderr; 199de566360SJordan K. Hubbard 200*f122045eSMartin Tournoij fprintf(out, 201*f122045eSMartin Tournoij "usage: %s program [args ...]\n" 202*f122045eSMartin Tournoij " %s --list\n" 203*f122045eSMartin Tournoij " program [args ...]\n" 204*f122045eSMartin Tournoij "\n" 205*f122045eSMartin Tournoij "%s combines several programs in one executable. Create a link to this\n" 206*f122045eSMartin Tournoij "executable with the program name to run that program, or give the program\n" 207*f122045eSMartin Tournoij "name as the first argument.\n" 208*f122045eSMartin Tournoij "\n" 209*f122045eSMartin Tournoij "Currently defined programs:\n", 210*f122045eSMartin Tournoij EXECNAME, EXECNAME, EXECNAME); 211de566360SJordan K. Hubbard columns = 0; 212*f122045eSMartin Tournoij for (int i = 0; i < num_entry_points - 2; i++) { 213*f122045eSMartin Tournoij struct stub *ep = &entry_points[i]; 214de566360SJordan K. Hubbard len = strlen(ep->name) + 1; 215de566360SJordan K. Hubbard if (columns + len < 80) 216de566360SJordan K. Hubbard columns += len; 217de566360SJordan K. Hubbard else { 218*f122045eSMartin Tournoij fprintf(out, "\n"); 219de566360SJordan K. Hubbard columns = len; 220de566360SJordan K. Hubbard } 221*f122045eSMartin Tournoij fprintf(out, " %s", ep->name); 222de566360SJordan K. Hubbard } 223*f122045eSMartin Tournoij fprintf(out, "\n"); 224*f122045eSMartin Tournoij exit(code); 225de566360SJordan K. Hubbard } 226de566360SJordan K. Hubbard 227de566360SJordan K. Hubbard /* end of crunched_main.c */ 228