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