1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 24 * 25 * Copyright (c) 1988 AT&T 26 * All Rights Reserved 27 * 28 * 29 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 30 * Use is subject to license terms. 31 */ 32 /* 33 * Copyright 2022 OmniOS Community Edition (OmniOSce) Association. 34 */ 35 36 #include "stdlib.h" 37 #include "conv.h" 38 #include "mcs.h" 39 #include "extern.h" 40 #define OPTUNIT 100 41 42 static size_t optcnt = 0; 43 static size_t optbufsz = OPTUNIT; 44 45 /* 46 * Function prototypes. 47 */ 48 static void usage(int); 49 static void sigexit(int); 50 static int setup_sectname(char *, int); 51 static void queue(int, char *); 52 53 int 54 main(int argc, char ** argv, char ** envp) 55 { 56 const char *opt; 57 char *str; 58 int error_count = 0, num_sect = 0, errflag = 0; 59 int c, i, my_prog; 60 Cmd_Info *cmd_info; 61 62 /* 63 * Check for a binary that better fits this architecture. 64 */ 65 (void) conv_check_native(argv, envp); 66 67 /* 68 * mcs(1) and strip() are hard linked together, determine which command 69 * was invoked. 70 */ 71 prog = argv[0]; 72 if ((str = strrchr(prog, '/')) != NULL) 73 str++; 74 else 75 str = prog; 76 77 if (strcmp(str, "mcs") == 0) { 78 my_prog = MCS; 79 opt = "a:cdn:pVz?"; 80 } else if (strcmp(str, "strip") == 0) { 81 my_prog = STRIP; 82 opt = "lxV?"; 83 } else 84 exit(FAILURE); 85 86 (void) setlocale(LC_ALL, ""); 87 #if !defined(TEXT_DOMAIN) 88 #define TEXT_DOMAIN "SYS_TEST" 89 #endif 90 (void) textdomain(TEXT_DOMAIN); 91 92 for (i = 0; signum[i]; i++) 93 if (signal(signum[i], SIG_IGN) != SIG_IGN) 94 (void) signal(signum[i], sigexit); 95 96 if ((Action = 97 malloc(optbufsz * sizeof (struct action))) == NULL) { 98 error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); 99 exit(FAILURE); 100 } 101 102 /* 103 * Allocate command info structure 104 */ 105 cmd_info = (Cmd_Info *) calloc(1, sizeof (Cmd_Info)); 106 if (cmd_info == NULL) { 107 error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); 108 exit(FAILURE); 109 } 110 if (my_prog == STRIP) 111 SET_OPT(cmd_info, I_AM_STRIP); 112 113 while ((c = getopt(argc, argv, (char *)opt)) != EOF) { 114 switch (c) { 115 case 'a': 116 optcnt++; 117 queue(ACT_APPEND, optarg); 118 SET_OPT(cmd_info, MIGHT_CHG | aFLAG); 119 cmd_info->str_size += strlen(optarg) + 1; 120 break; 121 case 'c': 122 optcnt++; 123 queue(ACT_COMPRESS, NULL); 124 SET_OPT(cmd_info, MIGHT_CHG | cFLAG); 125 break; 126 case 'd': 127 optcnt++; 128 if (!CHK_OPT(cmd_info, dFLAG)) 129 queue(ACT_DELETE, NULL); 130 SET_OPT(cmd_info, MIGHT_CHG | dFLAG); 131 break; 132 case 'z': 133 optcnt++; 134 queue(ACT_ZAP, NULL); 135 SET_OPT(cmd_info, MIGHT_CHG | zFLAG); 136 break; 137 case 'n': 138 (void) setup_sectname(optarg, my_prog); 139 num_sect++; 140 break; 141 case 'l': 142 optcnt++; 143 SET_OPT(cmd_info, lFLAG); 144 break; 145 case 'p': 146 optcnt++; 147 queue(ACT_PRINT, NULL); 148 SET_OPT(cmd_info, pFLAG); 149 break; 150 case 'x': 151 optcnt++; 152 SET_OPT(cmd_info, xFLAG); 153 break; 154 case 'V': 155 SET_OPT(cmd_info, VFLAG); 156 (void) fprintf(stderr, "%s: %s %s\n", prog, 157 (const char *)SGU_PKG, (const char *)SGU_REL); 158 break; 159 case '?': 160 errflag++; 161 break; 162 default: 163 break; 164 } 165 } 166 167 if (errflag) { 168 usage(my_prog); 169 exit(FAILURE); 170 } 171 172 /* 173 * strip command may not take any options. 174 */ 175 if (my_prog != STRIP) { 176 if (argc == optind && 177 (CHK_OPT(cmd_info, MIGHT_CHG) || CHK_OPT(cmd_info, pFLAG) || 178 argc == 1)) 179 usage(my_prog); 180 else if (!CHK_OPT(cmd_info, MIGHT_CHG) && 181 !CHK_OPT(cmd_info, pFLAG) && !CHK_OPT(cmd_info, VFLAG)) 182 usage(my_prog); 183 } 184 185 /* 186 * This version only allows multiple section names 187 * only for -d option. 188 */ 189 if ((num_sect >= 2) && (CHK_OPT(cmd_info, pFLAG) || 190 CHK_OPT(cmd_info, aFLAG) || 191 CHK_OPT(cmd_info, cFLAG))) { 192 error_message(USAGE_ERROR, PLAIN_ERROR, (char *)0, prog); 193 exit(FAILURE); 194 } 195 196 /* 197 * If no -n was specified, 198 * set the default, ".comment". 199 * This is for mcs only. 200 */ 201 if (num_sect == 0 && my_prog == MCS) { 202 (void) setup_sectname(".comment", MCS); 203 } 204 205 /* 206 * If I am strip command, then add needed 207 * section names. 208 */ 209 if (my_prog == STRIP) { 210 (void) setup_sectname(".line", MCS); 211 if (CHK_OPT(cmd_info, lFLAG) == 0) { 212 (void) setup_sectname(".debug", STRIP); 213 (void) setup_sectname(".stab", STRIP); 214 } 215 if (CHK_OPT(cmd_info, dFLAG) == 0) { 216 queue(ACT_DELETE, NULL); 217 SET_OPT(cmd_info, MIGHT_CHG | dFLAG); 218 } 219 } 220 221 (void) elf_version(EV_NONE); 222 if (elf_version(EV_CURRENT) == EV_NONE) { 223 error_message(ELFVER_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); 224 exit(FAILURE); 225 } 226 227 if (CHK_OPT(cmd_info, pFLAG) || CHK_OPT(cmd_info, MIGHT_CHG)) { 228 for (; optind < argc; optind++) { 229 error_count = error_count + 230 (each_file(argv[optind], cmd_info)); 231 } 232 } 233 234 mcs_exit(error_count); 235 /*NOTREACHED*/ 236 return (0); 237 } 238 239 /* 240 * Supplementary functions 241 */ 242 static void 243 queue(int activity, char *string) 244 { 245 if (optcnt > optbufsz) { 246 optbufsz = optbufsz * 2; 247 if ((Action = realloc((struct action *)Action, 248 optbufsz * sizeof (struct action))) == NULL) { 249 error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); 250 mcs_exit(FAILURE); 251 } 252 } 253 Action[actmax].a_action = activity; 254 Action[actmax].a_cnt = 0; 255 Action[actmax].a_string = string; 256 actmax++; 257 } 258 259 /* 260 * Reset a temporary file descriptor for reuse. 261 * If the file requires unlinking, that is done first. 262 */ 263 void 264 free_tempfile(Tmp_File *temp_file) 265 { 266 if ((temp_file->tmp_name != NULL) && (temp_file->tmp_unlink)) 267 (void) unlink(temp_file->tmp_name); 268 (void) memset(temp_file, 0, sizeof (*temp_file)); 269 } 270 271 /*ARGSUSED0*/ 272 static void 273 sigexit(int i) 274 { 275 free_tempfile(&artmpfile); 276 free_tempfile(&elftmpfile); 277 exit(100); 278 } 279 280 static void 281 usage(int me) 282 { 283 if (me == MCS) 284 (void) fprintf(stderr, gettext( 285 "usage: %s [-cdpVz] [-a string] [-n name] file ...\n"), prog); 286 else 287 (void) fprintf(stderr, gettext( 288 "usage: %s [-lVx] file ...\n"), prog); 289 mcs_exit(FAILURE); 290 } 291 292 void 293 mcs_exit(int val) 294 { 295 free_tempfile(&artmpfile); 296 free_tempfile(&elftmpfile); 297 exit(val); 298 } 299 300 /* 301 * Insert the section name 'name' into the 302 * section list. 303 */ 304 static int 305 setup_sectname(char *name, int whoami) 306 { 307 S_Name *new; 308 309 /* 310 * Check if the name is already specified or not. 311 */ 312 if ((whoami == MCS) && (sectcmp(name) == 0)) 313 return (0); 314 315 /* 316 * Allocate one 317 */ 318 if ((new = malloc(sizeof (S_Name))) == NULL) { 319 error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); 320 exit(FAILURE); 321 } 322 new->name = strdup(name); 323 if (new->name == NULL) { 324 error_message(USAGE_ERROR, PLAIN_ERROR, (char *)0, prog); 325 exit(FAILURE); 326 } 327 if (whoami == STRIP) 328 new->flags = SNAME_FLG_STRNCMP; 329 new->next = NULL; 330 331 /* 332 * Put this one in the list 333 */ 334 new->next = sect_head; 335 sect_head = new; 336 337 return (0); 338 } 339 340 /* 341 * Check if the 'name' exists in the section list. 342 * 343 * If found 344 * return 0; 345 * else 346 * return 1 347 */ 348 int 349 sectcmp(char *name) 350 { 351 /* 352 * Check if the name is already specified or not. 353 */ 354 if (sect_head != NULL) { 355 S_Name *p1 = sect_head; 356 while (p1 != NULL) { 357 if (p1->flags & SNAME_FLG_STRNCMP) { 358 if (strncmp(p1->name, 359 name, strlen(p1->name)) == 0) 360 return (0); 361 } else if (strcmp(p1->name, name) == 0) { 362 return (0); /* silently ignore */ 363 } 364 p1 = p1->next; 365 } 366 } 367 return (1); 368 } 369