xref: /illumos-gate/usr/src/cmd/sgs/mcs/common/main.c (revision a2f04351e04971ab0879872d264d6038c156b860)
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