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