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