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