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