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
main(int argc,char ** argv,char ** envp)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
queue(int activity,char * string)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
free_tempfile(Tmp_File * temp_file)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
sigexit(int i)273 sigexit(int i)
274 {
275 free_tempfile(&artmpfile);
276 free_tempfile(&elftmpfile);
277 exit(100);
278 }
279
280 static void
usage(int me)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
mcs_exit(int val)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
setup_sectname(char * name,int whoami)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
sectcmp(char * name)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