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
main(int argc,char ** argv,char ** envp)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
queue(int activity,char * string)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
free_tempfile(Tmp_File * temp_file)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
sigexit(int i)279 sigexit(int i)
280 {
281 free_tempfile(&artmpfile);
282 free_tempfile(&elftmpfile);
283 exit(100);
284 }
285
286 static void
usage(int me)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
mcs_exit(int val)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
setup_sectname(char * name,int whoami)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
sectcmp(char * name)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
check_swap()377 check_swap()
378 {
379 (void) system("/usr/sbin/swap -s");
380 }
381