/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2012 Nexenta Systems, Inc. All rights reserved. * * Copyright (c) 1988 AT&T * All Rights Reserved * * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright 2022 OmniOS Community Edition (OmniOSce) Association. */ #include "stdlib.h" #include "conv.h" #include "mcs.h" #include "extern.h" #define OPTUNIT 100 static size_t optcnt = 0; static size_t optbufsz = OPTUNIT; /* * Function prototypes. */ static void usage(int); static void sigexit(int); static int setup_sectname(char *, int); static void queue(int, char *); int main(int argc, char ** argv, char ** envp) { const char *opt; char *str; int error_count = 0, num_sect = 0, errflag = 0; int c, i, my_prog; Cmd_Info *cmd_info; /* * Check for a binary that better fits this architecture. */ (void) conv_check_native(argv, envp); /* * mcs(1) and strip() are hard linked together, determine which command * was invoked. */ prog = argv[0]; if ((str = strrchr(prog, '/')) != NULL) str++; else str = prog; if (strcmp(str, "mcs") == 0) { my_prog = MCS; opt = "a:cdn:pVz?"; } else if (strcmp(str, "strip") == 0) { my_prog = STRIP; opt = "lxV?"; } else exit(FAILURE); (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); for (i = 0; signum[i]; i++) if (signal(signum[i], SIG_IGN) != SIG_IGN) (void) signal(signum[i], sigexit); if ((Action = malloc(optbufsz * sizeof (struct action))) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); exit(FAILURE); } /* * Allocate command info structure */ cmd_info = (Cmd_Info *) calloc(1, sizeof (Cmd_Info)); if (cmd_info == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); exit(FAILURE); } if (my_prog == STRIP) SET_OPT(cmd_info, I_AM_STRIP); while ((c = getopt(argc, argv, (char *)opt)) != EOF) { switch (c) { case 'a': optcnt++; queue(ACT_APPEND, optarg); SET_OPT(cmd_info, MIGHT_CHG | aFLAG); cmd_info->str_size += strlen(optarg) + 1; break; case 'c': optcnt++; queue(ACT_COMPRESS, NULL); SET_OPT(cmd_info, MIGHT_CHG | cFLAG); break; case 'd': optcnt++; if (!CHK_OPT(cmd_info, dFLAG)) queue(ACT_DELETE, NULL); SET_OPT(cmd_info, MIGHT_CHG | dFLAG); break; case 'z': optcnt++; queue(ACT_ZAP, NULL); SET_OPT(cmd_info, MIGHT_CHG | zFLAG); break; case 'n': (void) setup_sectname(optarg, my_prog); num_sect++; break; case 'l': optcnt++; SET_OPT(cmd_info, lFLAG); break; case 'p': optcnt++; queue(ACT_PRINT, NULL); SET_OPT(cmd_info, pFLAG); break; case 'x': optcnt++; SET_OPT(cmd_info, xFLAG); break; case 'V': SET_OPT(cmd_info, VFLAG); (void) fprintf(stderr, "%s: %s %s\n", prog, (const char *)SGU_PKG, (const char *)SGU_REL); break; case '?': errflag++; break; default: break; } } if (errflag) { usage(my_prog); exit(FAILURE); } /* * strip command may not take any options. */ if (my_prog != STRIP) { if (argc == optind && (CHK_OPT(cmd_info, MIGHT_CHG) || CHK_OPT(cmd_info, pFLAG) || argc == 1)) usage(my_prog); else if (!CHK_OPT(cmd_info, MIGHT_CHG) && !CHK_OPT(cmd_info, pFLAG) && !CHK_OPT(cmd_info, VFLAG)) usage(my_prog); } /* * This version only allows multiple section names * only for -d option. */ if ((num_sect >= 2) && (CHK_OPT(cmd_info, pFLAG) || CHK_OPT(cmd_info, aFLAG) || CHK_OPT(cmd_info, cFLAG))) { error_message(USAGE_ERROR, PLAIN_ERROR, (char *)0, prog); exit(FAILURE); } /* * If no -n was specified, * set the default, ".comment". * This is for mcs only. */ if (num_sect == 0 && my_prog == MCS) { (void) setup_sectname(".comment", MCS); } /* * If I am strip command, then add needed * section names. */ if (my_prog == STRIP) { (void) setup_sectname(".line", MCS); if (CHK_OPT(cmd_info, lFLAG) == 0) { (void) setup_sectname(".debug", STRIP); (void) setup_sectname(".stab", STRIP); } if (CHK_OPT(cmd_info, dFLAG) == 0) { queue(ACT_DELETE, NULL); SET_OPT(cmd_info, MIGHT_CHG | dFLAG); } } (void) elf_version(EV_NONE); if (elf_version(EV_CURRENT) == EV_NONE) { error_message(ELFVER_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); exit(FAILURE); } if (CHK_OPT(cmd_info, pFLAG) || CHK_OPT(cmd_info, MIGHT_CHG)) { for (; optind < argc; optind++) { error_count = error_count + (each_file(argv[optind], cmd_info)); } } mcs_exit(error_count); /*NOTREACHED*/ return (0); } /* * Supplementary functions */ static void queue(int activity, char *string) { if (optcnt > optbufsz) { optbufsz = optbufsz * 2; if ((Action = realloc((struct action *)Action, optbufsz * sizeof (struct action))) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); mcs_exit(FAILURE); } } Action[actmax].a_action = activity; Action[actmax].a_cnt = 0; Action[actmax].a_string = string; actmax++; } /* * Reset a temporary file descriptor for reuse. * If the file requires unlinking, that is done first. */ void free_tempfile(Tmp_File *temp_file) { if ((temp_file->tmp_name != NULL) && (temp_file->tmp_unlink)) (void) unlink(temp_file->tmp_name); (void) memset(temp_file, 0, sizeof (*temp_file)); } /*ARGSUSED0*/ static void sigexit(int i) { free_tempfile(&artmpfile); free_tempfile(&elftmpfile); exit(100); } static void usage(int me) { if (me == MCS) (void) fprintf(stderr, gettext( "usage: %s [-cdpVz] [-a string] [-n name] file ...\n"), prog); else (void) fprintf(stderr, gettext( "usage: %s [-lVx] file ...\n"), prog); mcs_exit(FAILURE); } void mcs_exit(int val) { free_tempfile(&artmpfile); free_tempfile(&elftmpfile); exit(val); } /* * Insert the section name 'name' into the * section list. */ static int setup_sectname(char *name, int whoami) { S_Name *new; /* * Check if the name is already specified or not. */ if ((whoami == MCS) && (sectcmp(name) == 0)) return (0); /* * Allocate one */ if ((new = malloc(sizeof (S_Name))) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); exit(FAILURE); } new->name = strdup(name); if (new->name == NULL) { error_message(USAGE_ERROR, PLAIN_ERROR, (char *)0, prog); exit(FAILURE); } if (whoami == STRIP) new->flags = SNAME_FLG_STRNCMP; new->next = NULL; /* * Put this one in the list */ new->next = sect_head; sect_head = new; return (0); } /* * Check if the 'name' exists in the section list. * * If found * return 0; * else * return 1 */ int sectcmp(char *name) { /* * Check if the name is already specified or not. */ if (sect_head != NULL) { S_Name *p1 = sect_head; while (p1 != NULL) { if (p1->flags & SNAME_FLG_STRNCMP) { if (strncmp(p1->name, name, strlen(p1->name)) == 0) return (0); } else if (strcmp(p1->name, name) == 0) { return (0); /* silently ignore */ } p1 = p1->next; } } return (1); }