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
37static size_t optcnt = 0;
38static size_t optbufsz = OPTUNIT;
39
40/*
41 * Function prototypes.
42 */
43static void usage(int);
44static void sigexit(int);
45static int setup_sectname(char *, int);
46static void check_swap();
47static void queue(int, char *);
48
49int
50main(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 */
248static void
249queue(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 */
269void
270free_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*/
278static void
279sigexit(int i)
280{
281	free_tempfile(&artmpfile);
282	free_tempfile(&elftmpfile);
283	exit(100);
284}
285
286static void
287usage(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
298void
299mcs_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 */
310static int
311setup_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 */
354int
355sectcmp(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
376static void
377check_swap()
378{
379	(void) system("/usr/sbin/swap -s");
380}
381