xref: /illumos-gate/usr/src/tools/cw/cw.c (revision d17be682)
1aa9ef484SJohn Levon 
27c478bd9Sstevel@tonic-gate /*
37c478bd9Sstevel@tonic-gate  * CDDL HEADER START
47c478bd9Sstevel@tonic-gate  *
57c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
602e56f3fSwesolows  * Common Development and Distribution License (the "License").
702e56f3fSwesolows  * You may not use this file except in compliance with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
2202e56f3fSwesolows 
237c478bd9Sstevel@tonic-gate /*
247fbf8d03SScott Rotondo  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
261f5207b7SJohn Levon  *
27564d5236SRichard Lowe  * Copyright 2018 Richard Lowe.
281f5207b7SJohn Levon  * Copyright 2019 Joyent, Inc.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * Wrapper for the GNU C compiler to make it accept the Sun C compiler
337c478bd9Sstevel@tonic-gate  * arguments where possible.
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  * Since the translation is inexact, this is something of a work-in-progress.
369a70fc3bSMark J. Nelson  *
377c478bd9Sstevel@tonic-gate  */
387c478bd9Sstevel@tonic-gate 
395d9d9091SRichard Lowe /*
40*d17be682SRichard Lowe  * If you modify this file, you must increment CW_VERSION.  This is a semver,
41*d17be682SRichard Lowe  * incompatible changes should bump the major, anything else the minor.
425d9d9091SRichard Lowe  */
43*d17be682SRichard Lowe #define	CW_VERSION	"9.0"
449a70fc3bSMark J. Nelson 
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate  * -#		Verbose mode
477c478bd9Sstevel@tonic-gate  * -###		Show compiler commands built by driver, no compilation
487c478bd9Sstevel@tonic-gate  * -A<name[(tokens)]>	Preprocessor predicate assertion
497c478bd9Sstevel@tonic-gate  * -C		Prevent preprocessor from removing comments
507c478bd9Sstevel@tonic-gate  * -c		Compile only - produce .o files, suppress linking
517c478bd9Sstevel@tonic-gate  * -D<name[=token]>	Associate name with token as if by #define
527c478bd9Sstevel@tonic-gate  * -d[y|n]	dynamic [-dy] or static [-dn] option to linker
537c478bd9Sstevel@tonic-gate  * -E		Compile source through preprocessor only, output to stdout
547c478bd9Sstevel@tonic-gate  * -erroff=<t>	Suppress warnings specified by tags t(%none, %all, <tag list>)
557c478bd9Sstevel@tonic-gate  * -errtags=<a>	Display messages with tags a(no, yes)
567c478bd9Sstevel@tonic-gate  * -errwarn=<t>	Treats warnings specified by tags t(%none, %all, <tag list>)
577c478bd9Sstevel@tonic-gate  *		as errors
587c478bd9Sstevel@tonic-gate  * -g		Compile for debugging
597c478bd9Sstevel@tonic-gate  * -H		Print path name of each file included during compilation
607c478bd9Sstevel@tonic-gate  * -h <name>	Assign <name> to generated dynamic shared library
617c478bd9Sstevel@tonic-gate  * -I<dir>	Add <dir> to preprocessor #include file search path
627c478bd9Sstevel@tonic-gate  * -i		Passed to linker to ignore any LD_LIBRARY_PATH setting
637c478bd9Sstevel@tonic-gate  * -keeptmp	Keep temporary files created during compilation
647c478bd9Sstevel@tonic-gate  * -L<dir>	Pass to linker to add <dir> to the library search path
657c478bd9Sstevel@tonic-gate  * -l<name>	Link with library lib<name>.a or lib<name>.so
667c478bd9Sstevel@tonic-gate  * -mt		Specify options needed when compiling multi-threaded code
67662492f5Ssherrym  * -O		Use default optimization level (-xO2 or -xO3. Check man page.)
687c478bd9Sstevel@tonic-gate  * -o <outputfile> Set name of output file to <outputfile>
697c478bd9Sstevel@tonic-gate  * -P		Compile source through preprocessor only, output to .i  file
707c478bd9Sstevel@tonic-gate  * -p		Compile for profiling with prof
717c478bd9Sstevel@tonic-gate  * -R<dir[:dir]> Build runtime search path list into executable
727c478bd9Sstevel@tonic-gate  * -S		Compile and only generate assembly code (.s)
737c478bd9Sstevel@tonic-gate  * -s		Strip symbol table from the executable file
74159cf8a6Swesolows  * -t		Turn off duplicate symbol warnings when linking
757c478bd9Sstevel@tonic-gate  * -U<name>	Delete initial definition of preprocessor symbol <name>
767c478bd9Sstevel@tonic-gate  * -V		Report version number of each compilation phase
777c478bd9Sstevel@tonic-gate  * -v		Do stricter semantic checking
787c478bd9Sstevel@tonic-gate  * -W<c>,<arg>	Pass <arg> to specified component <c> (a,l,m,p,0,2,h,i,u)
797c478bd9Sstevel@tonic-gate  * -w		Suppress compiler warning messages
807c478bd9Sstevel@tonic-gate  * -Xa		Compile assuming ANSI C conformance, allow K & R extensions
817c478bd9Sstevel@tonic-gate  *		(default mode)
827c478bd9Sstevel@tonic-gate  * -Xs		Compile assuming (pre-ANSI) K & R C style code
837c478bd9Sstevel@tonic-gate  * -xarch=<a>	Specify target architecture instruction set
847c478bd9Sstevel@tonic-gate  * -xbuiltin[=<b>] When profitable inline, or substitute intrinisic functions
857c478bd9Sstevel@tonic-gate  *		for system functions, b={%all,%none}
867c478bd9Sstevel@tonic-gate  * -xchip=<c>	Specify the target processor for use by the optimizer
877c478bd9Sstevel@tonic-gate  * -xO<n>	Generate optimized code (n={1|2|3|4|5})
887c478bd9Sstevel@tonic-gate  * -xtarget=<t>	Specify target system for optimization
89*d17be682SRichard Lowe  * -YI,<dir>	Specify <dir> for location of headers
907c478bd9Sstevel@tonic-gate  */
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  * Translation table:
947c478bd9Sstevel@tonic-gate  */
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate  * -#				-v
977c478bd9Sstevel@tonic-gate  * -###				error
987c478bd9Sstevel@tonic-gate  * -A<name[(tokens)]>		pass-thru
997c478bd9Sstevel@tonic-gate  * -B<[static|dynamic]>		pass-thru (syntax error for anything else)
1007c478bd9Sstevel@tonic-gate  * -C				pass-thru
1017c478bd9Sstevel@tonic-gate  * -c				pass-thru
1027c478bd9Sstevel@tonic-gate  * -D<name[=token]>		pass-thru
1037c478bd9Sstevel@tonic-gate  * -E				pass-thru
1047c478bd9Sstevel@tonic-gate  * -errtags=%all		-Wall
1057c478bd9Sstevel@tonic-gate  * -errwarn=%all		-Werror else -Wno-error
1067c478bd9Sstevel@tonic-gate  * -g				pass-thru
1077c478bd9Sstevel@tonic-gate  * -H				pass-thru
1087c478bd9Sstevel@tonic-gate  * -I<dir>			pass-thru
1097c478bd9Sstevel@tonic-gate  * -i				pass-thru
1107c478bd9Sstevel@tonic-gate  * -keeptmp			-save-temps
1117c478bd9Sstevel@tonic-gate  * -L<dir>			pass-thru
1127c478bd9Sstevel@tonic-gate  * -l<name>			pass-thru
1137c478bd9Sstevel@tonic-gate  * -mt				-D_REENTRANT
1147c478bd9Sstevel@tonic-gate  * -nolib			-nodefaultlibs
115662492f5Ssherrym  * -O				-O1 (Check the man page to be certain)
1167c478bd9Sstevel@tonic-gate  * -o <outputfile>		pass-thru
1177c478bd9Sstevel@tonic-gate  * -P				-E -o filename.i (or error)
1187c478bd9Sstevel@tonic-gate  * -p				pass-thru
1197c478bd9Sstevel@tonic-gate  * -R<dir[:dir]>		pass-thru
1207c478bd9Sstevel@tonic-gate  * -S				pass-thru
1217c478bd9Sstevel@tonic-gate  * -U<name>			pass-thru
1227c478bd9Sstevel@tonic-gate  * -V				--version
1237c478bd9Sstevel@tonic-gate  * -v				-Wall
1247c478bd9Sstevel@tonic-gate  * -Wa,<arg>			pass-thru
125*d17be682SRichard Lowe  * -Wp,<arg>			pass-thru
1267c478bd9Sstevel@tonic-gate  * -Wl,<arg>			pass-thru
12754836668Spetede  * -xmodel=kernel		-ffreestanding -mcmodel=kernel -mno-red-zone
128d430274bSsherrym  * -Wu,-save_args		-msave-args
1297c478bd9Sstevel@tonic-gate  * -w				pass-thru
1307c478bd9Sstevel@tonic-gate  * -Xa				-std=iso9899:199409 or -ansi
1317c478bd9Sstevel@tonic-gate  * -Xs				-traditional -std=c89
1327c478bd9Sstevel@tonic-gate  * -xarch=<a>			table
13302e56f3fSwesolows  * -xbuiltin[=<b>]		-fbuiltin (-fno-builtin otherwise)
1347c478bd9Sstevel@tonic-gate  * -xchip=<c>			table
1357c478bd9Sstevel@tonic-gate  * -xO<n>			-O<n>
1367c478bd9Sstevel@tonic-gate  * -xtarget=<t>			table
1377c478bd9Sstevel@tonic-gate  * -xtransition			-Wtransition
1387c478bd9Sstevel@tonic-gate  * -YI,<dir>			-nostdinc -I<dir>
1397c478bd9Sstevel@tonic-gate  */
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate #include <ctype.h>
142aa9ef484SJohn Levon #include <err.h>
14380ab886dSwesolows #include <errno.h>
144aa9ef484SJohn Levon #include <fcntl.h>
145aa9ef484SJohn Levon #include <getopt.h>
146aa9ef484SJohn Levon #include <stdio.h>
147aa9ef484SJohn Levon #include <stdlib.h>
14822a8b493SToomas Soome #include <stdbool.h>
149aa9ef484SJohn Levon #include <string.h>
150aa9ef484SJohn Levon #include <unistd.h>
15188e61e85SRichard Lowe #include <dirent.h>
152aa9ef484SJohn Levon 
1537c478bd9Sstevel@tonic-gate #include <sys/param.h>
15480ab886dSwesolows #include <sys/stat.h>
155aa9ef484SJohn Levon #include <sys/types.h>
156aa9ef484SJohn Levon #include <sys/utsname.h>
157aa9ef484SJohn Levon #include <sys/wait.h>
15880ab886dSwesolows 
15980ab886dSwesolows #define	CW_F_CXX	0x01
16080ab886dSwesolows #define	CW_F_SHADOW	0x02
16180ab886dSwesolows #define	CW_F_EXEC	0x04
16280ab886dSwesolows #define	CW_F_ECHO	0x08
16380ab886dSwesolows #define	CW_F_XLATE	0x10
1641912d2c4Swesolows #define	CW_F_PROG	0x20
16580ab886dSwesolows 
16680ab886dSwesolows typedef enum cw_op {
16780ab886dSwesolows 	CW_O_NONE = 0,
16880ab886dSwesolows 	CW_O_PREPROCESS,
16980ab886dSwesolows 	CW_O_COMPILE,
17080ab886dSwesolows 	CW_O_LINK
17180ab886dSwesolows } cw_op_t;
17280ab886dSwesolows 
17380ab886dSwesolows struct aelist {
17480ab886dSwesolows 	struct ae {
17580ab886dSwesolows 		struct ae *ae_next;
17680ab886dSwesolows 		char *ae_arg;
17780ab886dSwesolows 	} *ael_head, *ael_tail;
17880ab886dSwesolows 	int ael_argc;
17980ab886dSwesolows };
18080ab886dSwesolows 
181aa9ef484SJohn Levon typedef enum {
182aa9ef484SJohn Levon 	GNU,
1831f5207b7SJohn Levon 	SUN,
1841f5207b7SJohn Levon 	SMATCH
185aa9ef484SJohn Levon } compiler_style_t;
186aa9ef484SJohn Levon 
187aa9ef484SJohn Levon typedef struct {
188aa9ef484SJohn Levon 	char *c_name;
189aa9ef484SJohn Levon 	char *c_path;
190aa9ef484SJohn Levon 	compiler_style_t c_style;
191aa9ef484SJohn Levon } cw_compiler_t;
192aa9ef484SJohn Levon 
19380ab886dSwesolows typedef struct cw_ictx {
194aa9ef484SJohn Levon 	struct cw_ictx	*i_next;
195aa9ef484SJohn Levon 	cw_compiler_t	*i_compiler;
19669b1fd3fSRichard Lowe 	char		*i_linker;
19780ab886dSwesolows 	struct aelist	*i_ae;
19880ab886dSwesolows 	uint32_t	i_flags;
19980ab886dSwesolows 	int		i_oldargc;
20080ab886dSwesolows 	char		**i_oldargv;
20180ab886dSwesolows 	pid_t		i_pid;
20288e61e85SRichard Lowe 	char		*i_tmpdir;
2031912d2c4Swesolows 	char		*i_stderr;
20480ab886dSwesolows } cw_ictx_t;
20580ab886dSwesolows 
206e521259dSpetede /*
207e521259dSpetede  * Status values to indicate which Studio compiler and associated
208e521259dSpetede  * flags are being used.
209e521259dSpetede  */
210e521259dSpetede #define	M32		0x01	/* -m32 - only on Studio 12 */
211e521259dSpetede #define	M64		0x02	/* -m64 - only on Studio 12 */
212e521259dSpetede #define	SS11		0x100	/* Studio 11 */
213e521259dSpetede #define	SS12		0x200	/* Studio 12 */
2147c478bd9Sstevel@tonic-gate 
215e521259dSpetede #define	TRANS_ENTRY	5
216e521259dSpetede /*
217e521259dSpetede  * Translation table definition for the -xarch= flag. The "x_arg"
218e521259dSpetede  * value is translated into the appropriate gcc flags according
219e521259dSpetede  * to the values in x_trans[n]. The x_flags indicates what compiler
220e521259dSpetede  * is being used and what flags have been set via the use of
221e521259dSpetede  * "x_arg".
222e521259dSpetede  */
223e521259dSpetede typedef struct xarch_table {
224e521259dSpetede 	char	*x_arg;
225e521259dSpetede 	int	x_flags;
226e521259dSpetede 	char	*x_trans[TRANS_ENTRY];
227e521259dSpetede } xarch_table_t;
228e521259dSpetede 
229e521259dSpetede /*
230e521259dSpetede  * The translation table for the -xarch= flag used in the Studio compilers.
231e521259dSpetede  */
232e521259dSpetede static const xarch_table_t xtbl[] = {
2337c478bd9Sstevel@tonic-gate #if defined(__x86)
234aa9ef484SJohn Levon 	{ "generic",	SS11, {NULL} },
2357a6460b6Spetede 	{ "generic64",	(SS11|M64), { "-m64", "-mtune=opteron" } },
2367a6460b6Spetede 	{ "amd64",	(SS11|M64), { "-m64", "-mtune=opteron" } },
2377a6460b6Spetede 	{ "386",	SS11,	{ "-march=i386" } },
2387a6460b6Spetede 	{ "pentium_pro", SS11,	{ "-march=pentiumpro" } },
23925c28e83SPiotr Jasiukajtis 	{ "sse",	SS11, { "-msse", "-mfpmath=sse" } },
24025c28e83SPiotr Jasiukajtis 	{ "sse2",	SS11, { "-msse2", "-mfpmath=sse" } },
2417c478bd9Sstevel@tonic-gate #endif
2427c478bd9Sstevel@tonic-gate };
2437c478bd9Sstevel@tonic-gate 
244e521259dSpetede static int xtbl_size = sizeof (xtbl) / sizeof (xarch_table_t);
245e521259dSpetede 
2467c478bd9Sstevel@tonic-gate static const char *xchip_tbl[] = {
2477c478bd9Sstevel@tonic-gate #if defined(__x86)
2487c478bd9Sstevel@tonic-gate 	"386",		"-mtune=i386", NULL,
2497c478bd9Sstevel@tonic-gate 	"486",		"-mtune=i486", NULL,
2507c478bd9Sstevel@tonic-gate 	"pentium",	"-mtune=pentium", NULL,
2517c478bd9Sstevel@tonic-gate 	"pentium_pro",  "-mtune=pentiumpro", NULL,
2527c478bd9Sstevel@tonic-gate #endif
2537c478bd9Sstevel@tonic-gate 	NULL,		NULL
2547c478bd9Sstevel@tonic-gate };
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate static const char *xtarget_tbl[] = {
2577c478bd9Sstevel@tonic-gate #if defined(__x86)
2587c478bd9Sstevel@tonic-gate 	"pentium_pro",	"-march=pentiumpro", NULL,
2597c478bd9Sstevel@tonic-gate #endif	/* __x86 */
2607c478bd9Sstevel@tonic-gate 	NULL,		NULL
2617c478bd9Sstevel@tonic-gate };
2627c478bd9Sstevel@tonic-gate 
26380ab886dSwesolows static void
nomem(void)26480ab886dSwesolows nomem(void)
26580ab886dSwesolows {
266aa9ef484SJohn Levon 	errx(1, "out of memory");
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate static void
newae(struct aelist * ael,const char * arg)2707c478bd9Sstevel@tonic-gate newae(struct aelist *ael, const char *arg)
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate 	struct ae *ae;
2737c478bd9Sstevel@tonic-gate 
27469b1fd3fSRichard Lowe 	if ((ae = calloc(1, sizeof (*ae))) == NULL)
27580ab886dSwesolows 		nomem();
2767c478bd9Sstevel@tonic-gate 	ae->ae_arg = strdup(arg);
2777c478bd9Sstevel@tonic-gate 	if (ael->ael_tail == NULL)
2787c478bd9Sstevel@tonic-gate 		ael->ael_head = ae;
2797c478bd9Sstevel@tonic-gate 	else
2807c478bd9Sstevel@tonic-gate 		ael->ael_tail->ae_next = ae;
2817c478bd9Sstevel@tonic-gate 	ael->ael_tail = ae;
28280ab886dSwesolows 	ael->ael_argc++;
28380ab886dSwesolows }
28480ab886dSwesolows 
28580ab886dSwesolows static cw_ictx_t *
newictx(void)28680ab886dSwesolows newictx(void)
28780ab886dSwesolows {
28869b1fd3fSRichard Lowe 	cw_ictx_t *ctx = calloc(1, sizeof (cw_ictx_t));
28980ab886dSwesolows 	if (ctx)
29069b1fd3fSRichard Lowe 		if ((ctx->i_ae = calloc(1, sizeof (struct aelist))) == NULL) {
29180ab886dSwesolows 			free(ctx);
29280ab886dSwesolows 			return (NULL);
29380ab886dSwesolows 		}
29480ab886dSwesolows 
29580ab886dSwesolows 	return (ctx);
2967c478bd9Sstevel@tonic-gate }
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate static void
error(const char * arg)2997c478bd9Sstevel@tonic-gate error(const char *arg)
3007c478bd9Sstevel@tonic-gate {
301aa9ef484SJohn Levon 	errx(2, "error: mapping failed at or near arg '%s'", arg);
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate /*
3057c478bd9Sstevel@tonic-gate  * Add the current favourite set of warnings to the gcc invocation.
3067c478bd9Sstevel@tonic-gate  */
3077c478bd9Sstevel@tonic-gate static void
warnings(struct aelist * h)3087c478bd9Sstevel@tonic-gate warnings(struct aelist *h)
3097c478bd9Sstevel@tonic-gate {
3107c478bd9Sstevel@tonic-gate 	static int warningsonce;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	if (warningsonce++)
3137c478bd9Sstevel@tonic-gate 		return;
3147c478bd9Sstevel@tonic-gate 
3157014882cSRichard Lowe 	/*
3167014882cSRichard Lowe 	 * Enable as many warnings as exist, then disable those that we never
3177014882cSRichard Lowe 	 * ever want.
3187014882cSRichard Lowe 	 */
3197c478bd9Sstevel@tonic-gate 	newae(h, "-Wall");
3207014882cSRichard Lowe 	newae(h, "-Wextra");
3217c478bd9Sstevel@tonic-gate }
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate static void
optim_disable(struct aelist * h,int level)3247c478bd9Sstevel@tonic-gate optim_disable(struct aelist *h, int level)
3257c478bd9Sstevel@tonic-gate {
3267c478bd9Sstevel@tonic-gate 	if (level >= 2) {
3277c478bd9Sstevel@tonic-gate 		newae(h, "-fno-strict-aliasing");
3287c478bd9Sstevel@tonic-gate 		newae(h, "-fno-unit-at-a-time");
3297c478bd9Sstevel@tonic-gate 		newae(h, "-fno-optimize-sibling-calls");
3307c478bd9Sstevel@tonic-gate 	}
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate static void
Xsmode(struct aelist * h)3347c478bd9Sstevel@tonic-gate Xsmode(struct aelist *h)
3357c478bd9Sstevel@tonic-gate {
3367c478bd9Sstevel@tonic-gate 	static int xsonce;
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	if (xsonce++)
3397c478bd9Sstevel@tonic-gate 		return;
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	newae(h, "-traditional");
3427c478bd9Sstevel@tonic-gate 	newae(h, "-traditional-cpp");
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate static void
usage(void)34669b1fd3fSRichard Lowe usage(void)
3477c478bd9Sstevel@tonic-gate {
348aa9ef484SJohn Levon 	extern char *__progname;
3497c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
350aa9ef484SJohn Levon 	    "usage: %s [-C] [--versions] --primary <compiler> "
351aa9ef484SJohn Levon 	    "[--shadow <compiler>]... -- cflags...\n",
352aa9ef484SJohn Levon 	    __progname);
353aa9ef484SJohn Levon 	(void) fprintf(stderr, "compilers take the form: name,path,style\n"
354aa9ef484SJohn Levon 	    " - name: a unique name usable in flag specifiers\n"
355aa9ef484SJohn Levon 	    " - path: path to the compiler binary\n"
356aa9ef484SJohn Levon 	    " - style: the style of flags expected: either sun or gnu\n");
3577c478bd9Sstevel@tonic-gate 	exit(2);
3587c478bd9Sstevel@tonic-gate }
3597c478bd9Sstevel@tonic-gate 
360e521259dSpetede static int
xlate_xtb(struct aelist * h,const char * xarg)361e521259dSpetede xlate_xtb(struct aelist *h, const char *xarg)
362e521259dSpetede {
363e521259dSpetede 	int	i, j;
364e521259dSpetede 
365e521259dSpetede 	for (i = 0; i < xtbl_size; i++) {
366e521259dSpetede 		if (strcmp(xtbl[i].x_arg, xarg) == 0)
367e521259dSpetede 			break;
368e521259dSpetede 	}
369e521259dSpetede 
370e521259dSpetede 	/*
371e521259dSpetede 	 * At the end of the table and so no matching "arg" entry
372e521259dSpetede 	 * found and so this must be a bad -xarch= flag.
373e521259dSpetede 	 */
374e521259dSpetede 	if (i == xtbl_size)
375e521259dSpetede 		error(xarg);
376e521259dSpetede 
377e521259dSpetede 	for (j = 0; j < TRANS_ENTRY; j++) {
378e521259dSpetede 		if (xtbl[i].x_trans[j] != NULL)
379e521259dSpetede 			newae(h, xtbl[i].x_trans[j]);
380e521259dSpetede 		else
381e521259dSpetede 			break;
382e521259dSpetede 	}
383e521259dSpetede 	return (xtbl[i].x_flags);
384e521259dSpetede 
385e521259dSpetede }
386e521259dSpetede 
3877c478bd9Sstevel@tonic-gate static void
xlate(struct aelist * h,const char * xarg,const char ** table)3887c478bd9Sstevel@tonic-gate xlate(struct aelist *h, const char *xarg, const char **table)
3897c478bd9Sstevel@tonic-gate {
3907c478bd9Sstevel@tonic-gate 	while (*table != NULL && strcmp(xarg, *table) != 0) {
3917c478bd9Sstevel@tonic-gate 		while (*table != NULL)
3927c478bd9Sstevel@tonic-gate 			table++;
3937c478bd9Sstevel@tonic-gate 		table++;
3947c478bd9Sstevel@tonic-gate 	}
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	if (*table == NULL)
3977c478bd9Sstevel@tonic-gate 		error(xarg);
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	table++;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	while (*table != NULL) {
4027c478bd9Sstevel@tonic-gate 		newae(h, *table);
4037c478bd9Sstevel@tonic-gate 		table++;
4047c478bd9Sstevel@tonic-gate 	}
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate 
40788e61e85SRichard Lowe /*
40888e61e85SRichard Lowe  * The compiler wants the output file to end in appropriate extension.  If
40988e61e85SRichard Lowe  * we're generating a name from whole cloth (path == NULL), we assume that
41088e61e85SRichard Lowe  * extension to be .o, otherwise we match the extension of the caller.
41188e61e85SRichard Lowe  */
41288e61e85SRichard Lowe static char *
discard_file_name(cw_ictx_t * ctx,const char * path)41388e61e85SRichard Lowe discard_file_name(cw_ictx_t *ctx, const char *path)
41488e61e85SRichard Lowe {
41588e61e85SRichard Lowe 	char *ret, *ext;
41688e61e85SRichard Lowe 	char tmpl[] = "cwXXXXXX";
41788e61e85SRichard Lowe 
41888e61e85SRichard Lowe 	if (path == NULL) {
41988e61e85SRichard Lowe 		ext = ".o";
42088e61e85SRichard Lowe 	} else {
42188e61e85SRichard Lowe 		ext = strrchr(path, '.');
42288e61e85SRichard Lowe 	}
42388e61e85SRichard Lowe 
42488e61e85SRichard Lowe 	/*
42588e61e85SRichard Lowe 	 * We need absolute control over where the temporary file goes, since
42688e61e85SRichard Lowe 	 * we rely on it for cleanup so tempnam(3C) and tmpnam(3C) are
42788e61e85SRichard Lowe 	 * inappropriate (they use TMPDIR, preferentially).
42888e61e85SRichard Lowe 	 *
42988e61e85SRichard Lowe 	 * mkstemp(3C) doesn't actually help us, since the temporary file
43088e61e85SRichard Lowe 	 * isn't used by us, only its name.
43188e61e85SRichard Lowe 	 */
43288e61e85SRichard Lowe 	if (mktemp(tmpl) == NULL)
43388e61e85SRichard Lowe 		nomem();
43488e61e85SRichard Lowe 
43588e61e85SRichard Lowe 	(void) asprintf(&ret, "%s/%s%s", ctx->i_tmpdir, tmpl,
43688e61e85SRichard Lowe 	    (ext != NULL) ? ext : "");
43788e61e85SRichard Lowe 
43888e61e85SRichard Lowe 	if (ret == NULL)
43988e61e85SRichard Lowe 		nomem();
44088e61e85SRichard Lowe 
44188e61e85SRichard Lowe 	return (ret);
44288e61e85SRichard Lowe }
44388e61e85SRichard Lowe 
44422a8b493SToomas Soome static bool
is_source_file(const char * path)44588e61e85SRichard Lowe is_source_file(const char *path)
44688e61e85SRichard Lowe {
44788e61e85SRichard Lowe 	char *ext = strrchr(path, '.');
44888e61e85SRichard Lowe 
449406d4d29SJohn Levon 	if ((ext == NULL) || (*(ext + 1) == '\0'))
45022a8b493SToomas Soome 		return (false);
45188e61e85SRichard Lowe 
45288e61e85SRichard Lowe 	ext += 1;
45388e61e85SRichard Lowe 
45488e61e85SRichard Lowe 	if ((strcasecmp(ext, "c") == 0) ||
45588e61e85SRichard Lowe 	    (strcmp(ext, "cc") == 0) ||
45688e61e85SRichard Lowe 	    (strcmp(ext, "i") == 0) ||
45788e61e85SRichard Lowe 	    (strcasecmp(ext, "s") == 0) ||
45888e61e85SRichard Lowe 	    (strcmp(ext, "cpp") == 0)) {
45922a8b493SToomas Soome 		return (true);
46088e61e85SRichard Lowe 	}
46188e61e85SRichard Lowe 
46222a8b493SToomas Soome 	return (false);
46388e61e85SRichard Lowe }
46488e61e85SRichard Lowe 
4655d9d9091SRichard Lowe static bool
is_asm_file(const char * path)4665d9d9091SRichard Lowe is_asm_file(const char *path)
4675d9d9091SRichard Lowe {
4685d9d9091SRichard Lowe 	char *ext = strrchr(path, '.');
4695d9d9091SRichard Lowe 
4705d9d9091SRichard Lowe 	if ((ext == NULL) || (*(ext + 1) == '\0'))
4715d9d9091SRichard Lowe 		return (false);
4725d9d9091SRichard Lowe 
4735d9d9091SRichard Lowe 	ext += 1;
4745d9d9091SRichard Lowe 
4755d9d9091SRichard Lowe 	if (strcasecmp(ext, "s") == 0)
4765d9d9091SRichard Lowe 		return (true);
4775d9d9091SRichard Lowe 
4785d9d9091SRichard Lowe 	return (false);
4795d9d9091SRichard Lowe }
48088e61e85SRichard Lowe 
4817c478bd9Sstevel@tonic-gate static void
do_gcc(cw_ictx_t * ctx)48280ab886dSwesolows do_gcc(cw_ictx_t *ctx)
4837c478bd9Sstevel@tonic-gate {
4847c478bd9Sstevel@tonic-gate 	int c;
485e1bf37b1SRichard Lowe 	int nolibc = 0;
48680ab886dSwesolows 	int in_output = 0, seen_o = 0, c_files = 0;
48780ab886dSwesolows 	cw_op_t op = CW_O_LINK;
4887c478bd9Sstevel@tonic-gate 	char *model = NULL;
489aa9ef484SJohn Levon 	char *nameflag;
49088e61e85SRichard Lowe 	int mflag = 0;
4917c478bd9Sstevel@tonic-gate 
4921912d2c4Swesolows 	if (ctx->i_flags & CW_F_PROG) {
4931912d2c4Swesolows 		newae(ctx->i_ae, "--version");
4941912d2c4Swesolows 		return;
4951912d2c4Swesolows 	}
4961912d2c4Swesolows 
49780ab886dSwesolows 	newae(ctx->i_ae, "-fident");
49880ab886dSwesolows 	newae(ctx->i_ae, "-finline");
49980ab886dSwesolows 	newae(ctx->i_ae, "-fno-inline-functions");
50080ab886dSwesolows 	newae(ctx->i_ae, "-fno-builtin");
50180ab886dSwesolows 	newae(ctx->i_ae, "-fno-asm");
5027014882cSRichard Lowe 	newae(ctx->i_ae, "-fdiagnostics-show-option");
50380ab886dSwesolows 	newae(ctx->i_ae, "-nodefaultlibs");
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	/*
5067c478bd9Sstevel@tonic-gate 	 * This is needed because 'u' is defined
5077c478bd9Sstevel@tonic-gate 	 * under a conditional on 'sun'.  Should
5087c478bd9Sstevel@tonic-gate 	 * probably just remove the conditional,
5097c478bd9Sstevel@tonic-gate 	 * or make it be dependent on '__sun'.
5107c478bd9Sstevel@tonic-gate 	 *
5117c478bd9Sstevel@tonic-gate 	 * -Dunix is also missing in enhanced ANSI mode
5127c478bd9Sstevel@tonic-gate 	 */
51380ab886dSwesolows 	newae(ctx->i_ae, "-D__sun");
5147c478bd9Sstevel@tonic-gate 
515aa9ef484SJohn Levon 	if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->c_name) == -1)
516aa9ef484SJohn Levon 		nomem();
517aa9ef484SJohn Levon 
5187c478bd9Sstevel@tonic-gate 	/*
5197c478bd9Sstevel@tonic-gate 	 * Walk the argument list, translating as we go ..
5207c478bd9Sstevel@tonic-gate 	 */
52180ab886dSwesolows 	while (--ctx->i_oldargc > 0) {
52280ab886dSwesolows 		char *arg = *++ctx->i_oldargv;
5237c478bd9Sstevel@tonic-gate 		size_t arglen = strlen(arg);
5247c478bd9Sstevel@tonic-gate 
52580ab886dSwesolows 		if (*arg == '-') {
5267c478bd9Sstevel@tonic-gate 			arglen--;
52780ab886dSwesolows 		} else {
52888e61e85SRichard Lowe 			if (!in_output && is_source_file(arg))
52980ab886dSwesolows 				c_files++;
53080ab886dSwesolows 
5317c478bd9Sstevel@tonic-gate 			/*
53280ab886dSwesolows 			 * Otherwise, filenames and partial arguments
53380ab886dSwesolows 			 * are passed through for gcc to chew on.  However,
53480ab886dSwesolows 			 * output is always discarded for the secondary
53580ab886dSwesolows 			 * compiler.
5367c478bd9Sstevel@tonic-gate 			 */
53788e61e85SRichard Lowe 			if ((ctx->i_flags & CW_F_SHADOW) && in_output) {
53888e61e85SRichard Lowe 				newae(ctx->i_ae, discard_file_name(ctx, arg));
53988e61e85SRichard Lowe 			} else {
54080ab886dSwesolows 				newae(ctx->i_ae, arg);
54188e61e85SRichard Lowe 			}
54280ab886dSwesolows 			in_output = 0;
5437c478bd9Sstevel@tonic-gate 			continue;
5447c478bd9Sstevel@tonic-gate 		}
5457c478bd9Sstevel@tonic-gate 
54680ab886dSwesolows 		if (ctx->i_flags & CW_F_CXX) {
547aa9ef484SJohn Levon 			if (strncmp(arg, "-_g++=", 6) == 0) {
548aa9ef484SJohn Levon 				newae(ctx->i_ae, strchr(arg, '=') + 1);
549aa9ef484SJohn Levon 				continue;
550aa9ef484SJohn Levon 			}
551*d17be682SRichard Lowe 
5527c478bd9Sstevel@tonic-gate 			if (strcmp(arg, "-xwe") == 0) {
5537c478bd9Sstevel@tonic-gate 				/* turn warnings into errors */
55480ab886dSwesolows 				newae(ctx->i_ae, "-Werror");
5557c478bd9Sstevel@tonic-gate 				continue;
5567c478bd9Sstevel@tonic-gate 			}
5577c478bd9Sstevel@tonic-gate 			if (strcmp(arg, "-nolib") == 0) {
5587c478bd9Sstevel@tonic-gate 				/* -nodefaultlibs is on by default */
5597c478bd9Sstevel@tonic-gate 				nolibc = 1;
5607c478bd9Sstevel@tonic-gate 				continue;
5617c478bd9Sstevel@tonic-gate 			}
5627c478bd9Sstevel@tonic-gate 		}
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 		switch ((c = arg[1])) {
5657c478bd9Sstevel@tonic-gate 		case '_':
566aa9ef484SJohn Levon 			if ((strncmp(arg, nameflag, strlen(nameflag)) == 0) ||
567aa9ef484SJohn Levon 			    (strncmp(arg, "-_gcc=", 6) == 0) ||
568aa9ef484SJohn Levon 			    (strncmp(arg, "-_gnu=", 6) == 0)) {
569aa9ef484SJohn Levon 				newae(ctx->i_ae, strchr(arg, '=') + 1);
570aa9ef484SJohn Levon 			}
5717c478bd9Sstevel@tonic-gate 			break;
5727c478bd9Sstevel@tonic-gate 		case '#':
5737c478bd9Sstevel@tonic-gate 			if (arglen == 1) {
57480ab886dSwesolows 				newae(ctx->i_ae, "-v");
5757c478bd9Sstevel@tonic-gate 				break;
5767c478bd9Sstevel@tonic-gate 			}
5777c478bd9Sstevel@tonic-gate 			error(arg);
5787c478bd9Sstevel@tonic-gate 			break;
579e1bf37b1SRichard Lowe 		case 'f':
580e1bf37b1SRichard Lowe 			if ((strcmp(arg, "-fpic") == 0) ||
581e1bf37b1SRichard Lowe 			    (strcmp(arg, "-fPIC") == 0)) {
582e1bf37b1SRichard Lowe 				newae(ctx->i_ae, arg);
583e1bf37b1SRichard Lowe 				break;
584e1bf37b1SRichard Lowe 			}
585e1bf37b1SRichard Lowe 			error(arg);
586e1bf37b1SRichard Lowe 			break;
5877c478bd9Sstevel@tonic-gate 		case 'E':
5887c478bd9Sstevel@tonic-gate 			if (arglen == 1) {
58980ab886dSwesolows 				newae(ctx->i_ae, "-xc");
59080ab886dSwesolows 				newae(ctx->i_ae, arg);
59180ab886dSwesolows 				op = CW_O_PREPROCESS;
5927c478bd9Sstevel@tonic-gate 				nolibc = 1;
5937c478bd9Sstevel@tonic-gate 				break;
5947c478bd9Sstevel@tonic-gate 			}
5957c478bd9Sstevel@tonic-gate 			error(arg);
5967c478bd9Sstevel@tonic-gate 			break;
5977c478bd9Sstevel@tonic-gate 		case 'c':
5987c478bd9Sstevel@tonic-gate 		case 'S':
59980ab886dSwesolows 			if (arglen == 1) {
60080ab886dSwesolows 				op = CW_O_COMPILE;
6017c478bd9Sstevel@tonic-gate 				nolibc = 1;
60280ab886dSwesolows 			}
6037c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
6047c478bd9Sstevel@tonic-gate 		case 'C':
6057c478bd9Sstevel@tonic-gate 		case 'H':
6067c478bd9Sstevel@tonic-gate 		case 'p':
6077c478bd9Sstevel@tonic-gate 			if (arglen == 1) {
60880ab886dSwesolows 				newae(ctx->i_ae, arg);
6097c478bd9Sstevel@tonic-gate 				break;
6107c478bd9Sstevel@tonic-gate 			}
6117c478bd9Sstevel@tonic-gate 			error(arg);
6127c478bd9Sstevel@tonic-gate 			break;
6137c478bd9Sstevel@tonic-gate 		case 'A':
614299e09deSRichard Lowe 		case 'g':
6157c478bd9Sstevel@tonic-gate 		case 'I':
6167c478bd9Sstevel@tonic-gate 		case 'i':
6177c478bd9Sstevel@tonic-gate 		case 'L':
6187c478bd9Sstevel@tonic-gate 		case 'l':
6197c478bd9Sstevel@tonic-gate 		case 'R':
6207c478bd9Sstevel@tonic-gate 		case 'U':
6217c478bd9Sstevel@tonic-gate 		case 'u':
6227c478bd9Sstevel@tonic-gate 		case 'w':
62380ab886dSwesolows 			newae(ctx->i_ae, arg);
62480ab886dSwesolows 			break;
62580ab886dSwesolows 		case 'o':
62680ab886dSwesolows 			seen_o = 1;
62780ab886dSwesolows 			if (arglen == 1) {
62880ab886dSwesolows 				in_output = 1;
62980ab886dSwesolows 				newae(ctx->i_ae, arg);
63080ab886dSwesolows 			} else if (ctx->i_flags & CW_F_SHADOW) {
63180ab886dSwesolows 				newae(ctx->i_ae, "-o");
63288e61e85SRichard Lowe 				newae(ctx->i_ae, discard_file_name(ctx, arg));
63380ab886dSwesolows 			} else {
63480ab886dSwesolows 				newae(ctx->i_ae, arg);
63580ab886dSwesolows 			}
6367c478bd9Sstevel@tonic-gate 			break;
6377c478bd9Sstevel@tonic-gate 		case 'D':
63880ab886dSwesolows 			newae(ctx->i_ae, arg);
6397c478bd9Sstevel@tonic-gate 			/*
6407c478bd9Sstevel@tonic-gate 			 * XXX	Clearly a hack ... do we need _KADB too?
6417c478bd9Sstevel@tonic-gate 			 */
6427c478bd9Sstevel@tonic-gate 			if (strcmp(arg, "-D_KERNEL") == 0 ||
6437c478bd9Sstevel@tonic-gate 			    strcmp(arg, "-D_BOOT") == 0)
64480ab886dSwesolows 				newae(ctx->i_ae, "-ffreestanding");
6457c478bd9Sstevel@tonic-gate 			break;
6467c478bd9Sstevel@tonic-gate 		case 'e':
6477c478bd9Sstevel@tonic-gate 			if (strcmp(arg, "-errtags=yes") == 0) {
64880ab886dSwesolows 				warnings(ctx->i_ae);
6497c478bd9Sstevel@tonic-gate 				break;
6507c478bd9Sstevel@tonic-gate 			}
6517c478bd9Sstevel@tonic-gate 			if (strcmp(arg, "-errwarn=%all") == 0) {
65280ab886dSwesolows 				newae(ctx->i_ae, "-Werror");
6537c478bd9Sstevel@tonic-gate 				break;
6547c478bd9Sstevel@tonic-gate 			}
6557c478bd9Sstevel@tonic-gate 			error(arg);
6567c478bd9Sstevel@tonic-gate 			break;
6577c478bd9Sstevel@tonic-gate 		case 'k':
6587c478bd9Sstevel@tonic-gate 			if (strcmp(arg, "-keeptmp") == 0) {
65980ab886dSwesolows 				newae(ctx->i_ae, "-save-temps");
6607c478bd9Sstevel@tonic-gate 				break;
6617c478bd9Sstevel@tonic-gate 			}
6627c478bd9Sstevel@tonic-gate 			error(arg);
6637c478bd9Sstevel@tonic-gate 			break;
6647c478bd9Sstevel@tonic-gate 		case 'm':
6657c478bd9Sstevel@tonic-gate 			if (strcmp(arg, "-mt") == 0) {
66680ab886dSwesolows 				newae(ctx->i_ae, "-D_REENTRANT");
6677c478bd9Sstevel@tonic-gate 				break;
6687c478bd9Sstevel@tonic-gate 			}
669e521259dSpetede 			if (strcmp(arg, "-m64") == 0) {
670e521259dSpetede 				newae(ctx->i_ae, "-m64");
671e521259dSpetede #if defined(__x86)
672e521259dSpetede 				newae(ctx->i_ae, "-mtune=opteron");
673e521259dSpetede #endif
674e521259dSpetede 				mflag |= M64;
675e521259dSpetede 				break;
676e521259dSpetede 			}
677e521259dSpetede 			if (strcmp(arg, "-m32") == 0) {
678e521259dSpetede 				newae(ctx->i_ae, "-m32");
679e521259dSpetede 				mflag |= M32;
680e521259dSpetede 				break;
681e521259dSpetede 			}
6827c478bd9Sstevel@tonic-gate 			error(arg);
6837c478bd9Sstevel@tonic-gate 			break;
6847c478bd9Sstevel@tonic-gate 		case 'O':
6857c478bd9Sstevel@tonic-gate 			if (arglen == 1) {
68680ab886dSwesolows 				newae(ctx->i_ae, "-O");
6877c478bd9Sstevel@tonic-gate 				break;
6887c478bd9Sstevel@tonic-gate 			}
6897c478bd9Sstevel@tonic-gate 			error(arg);
6907c478bd9Sstevel@tonic-gate 			break;
6917c478bd9Sstevel@tonic-gate 		case 'P':
6927c478bd9Sstevel@tonic-gate 			/*
6937c478bd9Sstevel@tonic-gate 			 * We could do '-E -o filename.i', but that's hard,
6947c478bd9Sstevel@tonic-gate 			 * and we don't need it for the case that's triggering
6957c478bd9Sstevel@tonic-gate 			 * this addition.  We'll require the user to specify
6967c478bd9Sstevel@tonic-gate 			 * -o in the Makefile.  If they don't they'll find out
6977c478bd9Sstevel@tonic-gate 			 * in a hurry.
6987c478bd9Sstevel@tonic-gate 			 */
69980ab886dSwesolows 			newae(ctx->i_ae, "-E");
70080ab886dSwesolows 			op = CW_O_PREPROCESS;
7017c478bd9Sstevel@tonic-gate 			nolibc = 1;
7027c478bd9Sstevel@tonic-gate 			break;
7037c478bd9Sstevel@tonic-gate 		case 's':
70485f4cb87SRichard Lowe 			if (strcmp(arg, "-shared") == 0) {
70585f4cb87SRichard Lowe 				newae(ctx->i_ae, "-shared");
70685f4cb87SRichard Lowe 				nolibc = 1;
707159cf8a6Swesolows 				break;
708159cf8a6Swesolows 			}
709159cf8a6Swesolows 			error(arg);
710159cf8a6Swesolows 			break;
71185f4cb87SRichard Lowe 
7127c478bd9Sstevel@tonic-gate 		case 'V':
7137c478bd9Sstevel@tonic-gate 			if (arglen == 1) {
71480ab886dSwesolows 				ctx->i_flags &= ~CW_F_ECHO;
71580ab886dSwesolows 				newae(ctx->i_ae, "--version");
7167c478bd9Sstevel@tonic-gate 				break;
7177c478bd9Sstevel@tonic-gate 			}
7187c478bd9Sstevel@tonic-gate 			error(arg);
7197c478bd9Sstevel@tonic-gate 			break;
7207c478bd9Sstevel@tonic-gate 		case 'v':
7217c478bd9Sstevel@tonic-gate 			if (arglen == 1) {
72280ab886dSwesolows 				warnings(ctx->i_ae);
7237c478bd9Sstevel@tonic-gate 				break;
7247c478bd9Sstevel@tonic-gate 			}
7257c478bd9Sstevel@tonic-gate 			error(arg);
7267c478bd9Sstevel@tonic-gate 			break;
7277c478bd9Sstevel@tonic-gate 		case 'W':
7287c478bd9Sstevel@tonic-gate 			if (strncmp(arg, "-Wa,", 4) == 0 ||
7297c478bd9Sstevel@tonic-gate 			    strncmp(arg, "-Wp,", 4) == 0 ||
7307c478bd9Sstevel@tonic-gate 			    strncmp(arg, "-Wl,", 4) == 0) {
73180ab886dSwesolows 				newae(ctx->i_ae, arg);
7327c478bd9Sstevel@tonic-gate 				break;
7337c478bd9Sstevel@tonic-gate 			}
734*d17be682SRichard Lowe 
7357c478bd9Sstevel@tonic-gate #if defined(__x86)
736d430274bSsherrym 			if (strcmp(arg, "-Wu,-save_args") == 0) {
73780ab886dSwesolows 				newae(ctx->i_ae, "-msave-args");
738d430274bSsherrym 				break;
739d430274bSsherrym 			}
7407c478bd9Sstevel@tonic-gate #endif	/* __x86 */
7417c478bd9Sstevel@tonic-gate 			error(arg);
7427c478bd9Sstevel@tonic-gate 			break;
7437c478bd9Sstevel@tonic-gate 		case 'X':
7447c478bd9Sstevel@tonic-gate 			if (strcmp(arg, "-Xs") == 0) {
74580ab886dSwesolows 				Xsmode(ctx->i_ae);
7467c478bd9Sstevel@tonic-gate 				break;
7477c478bd9Sstevel@tonic-gate 			}
7487c478bd9Sstevel@tonic-gate 			error(arg);
7497c478bd9Sstevel@tonic-gate 			break;
7507c478bd9Sstevel@tonic-gate 		case 'x':
7517c478bd9Sstevel@tonic-gate 			if (arglen == 1)
7527c478bd9Sstevel@tonic-gate 				error(arg);
7537c478bd9Sstevel@tonic-gate 			switch (arg[2]) {
7547c478bd9Sstevel@tonic-gate 			case 'a':
7557c478bd9Sstevel@tonic-gate 				if (strncmp(arg, "-xarch=", 7) == 0) {
756e521259dSpetede 					mflag |= xlate_xtb(ctx->i_ae, arg + 7);
7577c478bd9Sstevel@tonic-gate 					break;
7587c478bd9Sstevel@tonic-gate 				}
7597c478bd9Sstevel@tonic-gate 				error(arg);
7607c478bd9Sstevel@tonic-gate 				break;
76102e56f3fSwesolows 			case 'b':
76202e56f3fSwesolows 				if (strncmp(arg, "-xbuiltin=", 10) == 0) {
76302e56f3fSwesolows 					if (strcmp(arg + 10, "%all"))
76480ab886dSwesolows 						newae(ctx->i_ae, "-fbuiltin");
76502e56f3fSwesolows 					break;
76602e56f3fSwesolows 				}
76702e56f3fSwesolows 				error(arg);
76802e56f3fSwesolows 				break;
7697c478bd9Sstevel@tonic-gate 			case 'c':
7707c478bd9Sstevel@tonic-gate 				if (strncmp(arg, "-xc99=%all", 10) == 0) {
77180ab886dSwesolows 					newae(ctx->i_ae, "-std=gnu99");
7727c478bd9Sstevel@tonic-gate 					break;
7737c478bd9Sstevel@tonic-gate 				}
7747c478bd9Sstevel@tonic-gate 				if (strncmp(arg, "-xc99=%none", 11) == 0) {
77580ab886dSwesolows 					newae(ctx->i_ae, "-std=gnu89");
7767c478bd9Sstevel@tonic-gate 					break;
7777c478bd9Sstevel@tonic-gate 				}
7787c478bd9Sstevel@tonic-gate 				if (strncmp(arg, "-xchip=", 7) == 0) {
77980ab886dSwesolows 					xlate(ctx->i_ae, arg + 7, xchip_tbl);
7807c478bd9Sstevel@tonic-gate 					break;
7817c478bd9Sstevel@tonic-gate 				}
782*d17be682SRichard Lowe 
7837c478bd9Sstevel@tonic-gate 				error(arg);
7847c478bd9Sstevel@tonic-gate 				break;
78554836668Spetede #if defined(__x86)
78654836668Spetede 			case 'm':
78754836668Spetede 				if (strcmp(arg, "-xmodel=kernel") == 0) {
78854836668Spetede 					newae(ctx->i_ae, "-ffreestanding");
78954836668Spetede 					newae(ctx->i_ae, "-mno-red-zone");
79054836668Spetede 					model = "-mcmodel=kernel";
79154836668Spetede 					nolibc = 1;
79254836668Spetede 					break;
79354836668Spetede 				}
79454836668Spetede 				error(arg);
79554836668Spetede 				break;
79654836668Spetede #endif	/* __x86 */
7977c478bd9Sstevel@tonic-gate 			case 'O':
7987c478bd9Sstevel@tonic-gate 				if (strncmp(arg, "-xO", 3) == 0) {
7997c478bd9Sstevel@tonic-gate 					size_t len = strlen(arg);
800538ff303SToomas Soome 					char *s = NULL;
8017c478bd9Sstevel@tonic-gate 					int c = *(arg + 3);
8027c478bd9Sstevel@tonic-gate 					int level;
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 					if (len != 4 || !isdigit(c))
8057c478bd9Sstevel@tonic-gate 						error(arg);
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 					level = atoi(arg + 3);
8087c478bd9Sstevel@tonic-gate 					if (level > 5)
8097c478bd9Sstevel@tonic-gate 						error(arg);
8107c478bd9Sstevel@tonic-gate 					if (level >= 2) {
8117c478bd9Sstevel@tonic-gate 						/*
8127c478bd9Sstevel@tonic-gate 						 * For gcc-3.4.x at -O2 we
8137c478bd9Sstevel@tonic-gate 						 * need to disable optimizations
8147c478bd9Sstevel@tonic-gate 						 * that break ON.
8157c478bd9Sstevel@tonic-gate 						 */
81680ab886dSwesolows 						optim_disable(ctx->i_ae, level);
8177c478bd9Sstevel@tonic-gate 						/*
8187c478bd9Sstevel@tonic-gate 						 * limit -xO3 to -O2 as well.
8197c478bd9Sstevel@tonic-gate 						 */
8207c478bd9Sstevel@tonic-gate 						level = 2;
8217c478bd9Sstevel@tonic-gate 					}
822538ff303SToomas Soome 					if (asprintf(&s, "-O%d", level) == -1)
823538ff303SToomas Soome 						nomem();
82480ab886dSwesolows 					newae(ctx->i_ae, s);
8257c478bd9Sstevel@tonic-gate 					free(s);
8267c478bd9Sstevel@tonic-gate 					break;
8277c478bd9Sstevel@tonic-gate 				}
8287c478bd9Sstevel@tonic-gate 				error(arg);
8297c478bd9Sstevel@tonic-gate 				break;
8307c478bd9Sstevel@tonic-gate 			case 't':
8317c478bd9Sstevel@tonic-gate 				if (strncmp(arg, "-xtarget=", 9) == 0) {
83280ab886dSwesolows 					xlate(ctx->i_ae, arg + 9, xtarget_tbl);
8337c478bd9Sstevel@tonic-gate 					break;
8347c478bd9Sstevel@tonic-gate 				}
8357c478bd9Sstevel@tonic-gate 				error(arg);
8367c478bd9Sstevel@tonic-gate 				break;
8377c478bd9Sstevel@tonic-gate 			default:
8387c478bd9Sstevel@tonic-gate 				error(arg);
8397c478bd9Sstevel@tonic-gate 				break;
8407c478bd9Sstevel@tonic-gate 			}
8417c478bd9Sstevel@tonic-gate 			break;
8427c478bd9Sstevel@tonic-gate 		case 'Y':
8437c478bd9Sstevel@tonic-gate 			if (arglen == 1) {
84480ab886dSwesolows 				if ((arg = *++ctx->i_oldargv) == NULL ||
84580ab886dSwesolows 				    *arg == '\0')
8467c478bd9Sstevel@tonic-gate 					error("-Y");
84780ab886dSwesolows 				ctx->i_oldargc--;
8487c478bd9Sstevel@tonic-gate 				arglen = strlen(arg + 1);
8497c478bd9Sstevel@tonic-gate 			} else {
8507c478bd9Sstevel@tonic-gate 				arg += 2;
8517c478bd9Sstevel@tonic-gate 			}
8527c478bd9Sstevel@tonic-gate 			if (strncmp(arg, "I,", 2) == 0) {
8537c478bd9Sstevel@tonic-gate 				char *s = strdup(arg);
8547c478bd9Sstevel@tonic-gate 				s[0] = '-';
8557c478bd9Sstevel@tonic-gate 				s[1] = 'I';
85680ab886dSwesolows 				newae(ctx->i_ae, "-nostdinc");
85780ab886dSwesolows 				newae(ctx->i_ae, s);
8587c478bd9Sstevel@tonic-gate 				free(s);
8597c478bd9Sstevel@tonic-gate 				break;
8607c478bd9Sstevel@tonic-gate 			}
8617c478bd9Sstevel@tonic-gate 			error(arg);
8627c478bd9Sstevel@tonic-gate 			break;
8637c478bd9Sstevel@tonic-gate 		default:
8647c478bd9Sstevel@tonic-gate 			error(arg);
8657c478bd9Sstevel@tonic-gate 			break;
8667c478bd9Sstevel@tonic-gate 		}
8677c478bd9Sstevel@tonic-gate 	}
8687c478bd9Sstevel@tonic-gate 
869aa9ef484SJohn Levon 	free(nameflag);
870aa9ef484SJohn Levon 
87188e61e85SRichard Lowe 	/*
87288e61e85SRichard Lowe 	 * When compiling multiple source files in a single invocation some
87388e61e85SRichard Lowe 	 * compilers output objects into the current directory with
87488e61e85SRichard Lowe 	 * predictable and conventional names.
87588e61e85SRichard Lowe 	 *
87688e61e85SRichard Lowe 	 * We prevent any attempt to compile multiple files at once so that
87788e61e85SRichard Lowe 	 * any such objects created by a shadow can't escape into a later
87888e61e85SRichard Lowe 	 * link-edit.
87988e61e85SRichard Lowe 	 */
88088e61e85SRichard Lowe 	if (c_files > 1 && op != CW_O_PREPROCESS) {
881aa9ef484SJohn Levon 		errx(2, "multiple source files are "
882aa9ef484SJohn Levon 		    "allowed only with -E or -P");
88380ab886dSwesolows 	}
884e521259dSpetede 
885e521259dSpetede 	/*
886e521259dSpetede 	 * Make sure that we do not have any unintended interactions between
887e521259dSpetede 	 * the xarch options passed in and the version of the Studio compiler
888e521259dSpetede 	 * used.
889e521259dSpetede 	 */
890e521259dSpetede 	if ((mflag & (SS11|SS12)) == (SS11|SS12)) {
891aa9ef484SJohn Levon 		errx(2,
892e521259dSpetede 		    "Conflicting \"-xarch=\" flags (both Studio 11 and 12)\n");
893e521259dSpetede 	}
894e521259dSpetede 
895e521259dSpetede 	switch (mflag) {
896e521259dSpetede 	case 0:
897e521259dSpetede 	case M32:
898e521259dSpetede 	case M64:
899e521259dSpetede 	case SS12:
900e521259dSpetede 	case SS11:
901e521259dSpetede 	case (SS11|M32):
902e521259dSpetede 	case (SS11|M64):
903e521259dSpetede 	case (SS12|M32):
904e521259dSpetede 	case (SS12|M64):
905e521259dSpetede 		break;
906e521259dSpetede 	default:
907e521259dSpetede 		(void) fprintf(stderr,
9087a6460b6Spetede 		    "Incompatible -xarch= and/or -m32/-m64 options used.\n");
909e521259dSpetede 		exit(2);
910e521259dSpetede 	}
911aa9ef484SJohn Levon 
91288e61e85SRichard Lowe 	if (ctx->i_flags & CW_F_SHADOW) {
91388e61e85SRichard Lowe 		if (op == CW_O_PREPROCESS)
91488e61e85SRichard Lowe 			exit(0);
91588e61e85SRichard Lowe 		else if (op == CW_O_LINK && c_files == 0)
91688e61e85SRichard Lowe 			exit(0);
91788e61e85SRichard Lowe 	}
91880ab886dSwesolows 
919e1bf37b1SRichard Lowe 	if (model != NULL)
92080ab886dSwesolows 		newae(ctx->i_ae, model);
9217c478bd9Sstevel@tonic-gate 	if (!nolibc)
92280ab886dSwesolows 		newae(ctx->i_ae, "-lc");
92380ab886dSwesolows 	if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
92480ab886dSwesolows 		newae(ctx->i_ae, "-o");
92588e61e85SRichard Lowe 		newae(ctx->i_ae, discard_file_name(ctx, NULL));
92680ab886dSwesolows 	}
92780ab886dSwesolows }
92880ab886dSwesolows 
9291f5207b7SJohn Levon static void
do_smatch(cw_ictx_t * ctx)9301f5207b7SJohn Levon do_smatch(cw_ictx_t *ctx)
9311f5207b7SJohn Levon {
9321f5207b7SJohn Levon 	if (ctx->i_flags & CW_F_PROG) {
9331f5207b7SJohn Levon 		newae(ctx->i_ae, "--version");
9341f5207b7SJohn Levon 		return;
9351f5207b7SJohn Levon 	}
9361f5207b7SJohn Levon 
9371f5207b7SJohn Levon 	/*
9381f5207b7SJohn Levon 	 * Some sources shouldn't run smatch at all.
9391f5207b7SJohn Levon 	 */
9401f5207b7SJohn Levon 	for (int i = 0; i < ctx->i_oldargc; i++) {
9411f5207b7SJohn Levon 		char *arg = ctx->i_oldargv[i];
9421f5207b7SJohn Levon 
9431f5207b7SJohn Levon 		if (strcmp(arg, "-_smatch=off") == 0) {
9445d9d9091SRichard Lowe 			ctx->i_flags &= ~(CW_F_EXEC | CW_F_ECHO);
9455d9d9091SRichard Lowe 			return;
9465d9d9091SRichard Lowe 		}
9475d9d9091SRichard Lowe 
9485d9d9091SRichard Lowe 		/* smatch can't handle asm */
9495d9d9091SRichard Lowe 		if ((arg[0] != '-') && is_asm_file(arg)) {
9505d9d9091SRichard Lowe 			ctx->i_flags &= ~(CW_F_EXEC | CW_F_ECHO);
9511f5207b7SJohn Levon 			return;
9521f5207b7SJohn Levon 		}
9531f5207b7SJohn Levon 	}
9541f5207b7SJohn Levon 
9551f5207b7SJohn Levon 	/*
9561f5207b7SJohn Levon 	 * smatch can handle gcc's options.
9571f5207b7SJohn Levon 	 */
9581f5207b7SJohn Levon 	do_gcc(ctx);
9591f5207b7SJohn Levon }
9601f5207b7SJohn Levon 
96180ab886dSwesolows static void
do_cc(cw_ictx_t * ctx)96280ab886dSwesolows do_cc(cw_ictx_t *ctx)
96380ab886dSwesolows {
96488e61e85SRichard Lowe 	int in_output = 0, seen_o = 0, c_files = 0;
96580ab886dSwesolows 	cw_op_t op = CW_O_LINK;
966aa9ef484SJohn Levon 	char *nameflag;
96780ab886dSwesolows 
9681912d2c4Swesolows 	if (ctx->i_flags & CW_F_PROG) {
9691912d2c4Swesolows 		newae(ctx->i_ae, "-V");
9701912d2c4Swesolows 		return;
9711912d2c4Swesolows 	}
9721912d2c4Swesolows 
973aa9ef484SJohn Levon 	if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->c_name) == -1)
974aa9ef484SJohn Levon 		nomem();
975aa9ef484SJohn Levon 
97680ab886dSwesolows 	while (--ctx->i_oldargc > 0) {
97780ab886dSwesolows 		char *arg = *++ctx->i_oldargv;
97880ab886dSwesolows 
979aa9ef484SJohn Levon 		if (strncmp(arg, "-_CC=", 5) == 0) {
980aa9ef484SJohn Levon 			newae(ctx->i_ae, strchr(arg, '=') + 1);
981aa9ef484SJohn Levon 			continue;
982aa9ef484SJohn Levon 		}
983aa9ef484SJohn Levon 
98480ab886dSwesolows 		if (*arg != '-') {
98588e61e85SRichard Lowe 			if (!in_output && is_source_file(arg))
98688e61e85SRichard Lowe 				c_files++;
98788e61e85SRichard Lowe 
98880ab886dSwesolows 			if (in_output == 0 || !(ctx->i_flags & CW_F_SHADOW)) {
98980ab886dSwesolows 				newae(ctx->i_ae, arg);
99080ab886dSwesolows 			} else {
99180ab886dSwesolows 				in_output = 0;
99288e61e85SRichard Lowe 				newae(ctx->i_ae, discard_file_name(ctx, arg));
99380ab886dSwesolows 			}
99480ab886dSwesolows 			continue;
99580ab886dSwesolows 		}
99680ab886dSwesolows 		switch (*(arg + 1)) {
99780ab886dSwesolows 		case '_':
998aa9ef484SJohn Levon 			if ((strncmp(arg, nameflag, strlen(nameflag)) == 0) ||
999aa9ef484SJohn Levon 			    (strncmp(arg, "-_cc=", 5) == 0) ||
1000aa9ef484SJohn Levon 			    (strncmp(arg, "-_sun=", 6) == 0)) {
1001aa9ef484SJohn Levon 				newae(ctx->i_ae, strchr(arg, '=') + 1);
100280ab886dSwesolows 			}
100380ab886dSwesolows 			break;
1004aa9ef484SJohn Levon 
100580ab886dSwesolows 		case 'V':
100680ab886dSwesolows 			ctx->i_flags &= ~CW_F_ECHO;
100780ab886dSwesolows 			newae(ctx->i_ae, arg);
100880ab886dSwesolows 			break;
100980ab886dSwesolows 		case 'o':
101080ab886dSwesolows 			seen_o = 1;
101180ab886dSwesolows 			if (strlen(arg) == 2) {
101280ab886dSwesolows 				in_output = 1;
101380ab886dSwesolows 				newae(ctx->i_ae, arg);
101480ab886dSwesolows 			} else if (ctx->i_flags & CW_F_SHADOW) {
101580ab886dSwesolows 				newae(ctx->i_ae, "-o");
101688e61e85SRichard Lowe 				newae(ctx->i_ae, discard_file_name(ctx, arg));
101780ab886dSwesolows 			} else {
101880ab886dSwesolows 				newae(ctx->i_ae, arg);
101980ab886dSwesolows 			}
102080ab886dSwesolows 			break;
102180ab886dSwesolows 		case 'c':
102280ab886dSwesolows 		case 'S':
10230bb3415fSrie 			if (strlen(arg) == 2)
10240bb3415fSrie 				op = CW_O_COMPILE;
102580ab886dSwesolows 			newae(ctx->i_ae, arg);
102680ab886dSwesolows 			break;
102780ab886dSwesolows 		case 'E':
102880ab886dSwesolows 		case 'P':
10290bb3415fSrie 			if (strlen(arg) == 2)
10300bb3415fSrie 				op = CW_O_PREPROCESS;
103180ab886dSwesolows 		/*FALLTHROUGH*/
103280ab886dSwesolows 		default:
103380ab886dSwesolows 			newae(ctx->i_ae, arg);
103480ab886dSwesolows 		}
103580ab886dSwesolows 	}
103680ab886dSwesolows 
1037aa9ef484SJohn Levon 	free(nameflag);
1038aa9ef484SJohn Levon 
103988e61e85SRichard Lowe 	/* See the comment on this same code in do_gcc() */
104088e61e85SRichard Lowe 	if (c_files > 1 && op != CW_O_PREPROCESS) {
104188e61e85SRichard Lowe 		errx(2, "multiple source files are "
104288e61e85SRichard Lowe 		    "allowed only with -E or -P");
104388e61e85SRichard Lowe 	}
104488e61e85SRichard Lowe 
104588e61e85SRichard Lowe 	if (ctx->i_flags & CW_F_SHADOW) {
104688e61e85SRichard Lowe 		if (op == CW_O_PREPROCESS)
104788e61e85SRichard Lowe 			exit(0);
104888e61e85SRichard Lowe 		else if (op == CW_O_LINK && c_files == 0)
104988e61e85SRichard Lowe 			exit(0);
105088e61e85SRichard Lowe 	}
105180ab886dSwesolows 
105280ab886dSwesolows 	if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
105380ab886dSwesolows 		newae(ctx->i_ae, "-o");
105488e61e85SRichard Lowe 		newae(ctx->i_ae, discard_file_name(ctx, NULL));
105580ab886dSwesolows 	}
10567c478bd9Sstevel@tonic-gate }
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate static void
prepctx(cw_ictx_t * ctx)105980ab886dSwesolows prepctx(cw_ictx_t *ctx)
10607c478bd9Sstevel@tonic-gate {
1061aa9ef484SJohn Levon 	newae(ctx->i_ae, ctx->i_compiler->c_path);
106280ab886dSwesolows 
10631912d2c4Swesolows 	if (ctx->i_flags & CW_F_PROG) {
10641912d2c4Swesolows 		(void) printf("%s: %s\n", (ctx->i_flags & CW_F_SHADOW) ?
1065aa9ef484SJohn Levon 		    "shadow" : "primary", ctx->i_compiler->c_path);
10661912d2c4Swesolows 		(void) fflush(stdout);
10671912d2c4Swesolows 	}
10681912d2c4Swesolows 
106969b1fd3fSRichard Lowe 	/*
107069b1fd3fSRichard Lowe 	 * If LD_ALTEXEC is already set, the expectation would be that that
107169b1fd3fSRichard Lowe 	 * link-editor is run, as such we need to leave it the environment
107269b1fd3fSRichard Lowe 	 * alone and let that happen.
107369b1fd3fSRichard Lowe 	 */
107469b1fd3fSRichard Lowe 	if ((ctx->i_linker != NULL) && (getenv("LD_ALTEXEC") == NULL))
107569b1fd3fSRichard Lowe 		setenv("LD_ALTEXEC", ctx->i_linker, 1);
107669b1fd3fSRichard Lowe 
107780ab886dSwesolows 	if (!(ctx->i_flags & CW_F_XLATE))
107880ab886dSwesolows 		return;
107980ab886dSwesolows 
1080aa9ef484SJohn Levon 	switch (ctx->i_compiler->c_style) {
1081aa9ef484SJohn Levon 	case SUN:
108280ab886dSwesolows 		do_cc(ctx);
108380ab886dSwesolows 		break;
1084aa9ef484SJohn Levon 	case GNU:
108580ab886dSwesolows 		do_gcc(ctx);
108680ab886dSwesolows 		break;
10871f5207b7SJohn Levon 	case SMATCH:
10881f5207b7SJohn Levon 		do_smatch(ctx);
10891f5207b7SJohn Levon 		break;
109080ab886dSwesolows 	}
109180ab886dSwesolows }
109280ab886dSwesolows 
109380ab886dSwesolows static int
invoke(cw_ictx_t * ctx)109480ab886dSwesolows invoke(cw_ictx_t *ctx)
109580ab886dSwesolows {
1096c3d5f7c4SRyan Goodfellow 	char **newargv, *makeflags;
109780ab886dSwesolows 	int ac;
109880ab886dSwesolows 	struct ae *a;
109980ab886dSwesolows 
1100c3d5f7c4SRyan Goodfellow 	newargv = calloc(ctx->i_ae->ael_argc + 1, sizeof (*newargv));
1101c3d5f7c4SRyan Goodfellow 	if (newargv == NULL)
110280ab886dSwesolows 		nomem();
110380ab886dSwesolows 
1104c3d5f7c4SRyan Goodfellow 	/*
1105c3d5f7c4SRyan Goodfellow 	 * Check to see if the silent make flag is present (-s), if so, do not
1106c3d5f7c4SRyan Goodfellow 	 * echo. The MAKEFLAGS environment variable is set by dmake. By
1107c3d5f7c4SRyan Goodfellow 	 * observation it appears to place short flags without any arguments
1108c3d5f7c4SRyan Goodfellow 	 * first followed by any long form flags or flags with arguments.
1109c3d5f7c4SRyan Goodfellow 	 */
1110c3d5f7c4SRyan Goodfellow 	makeflags = getenv("MAKEFLAGS");
1111c3d5f7c4SRyan Goodfellow 	if (makeflags != NULL) {
1112c3d5f7c4SRyan Goodfellow 		size_t makeflags_len = strlen(makeflags);
1113c3d5f7c4SRyan Goodfellow 		for (size_t i = 0; i < makeflags_len; i++) {
1114c3d5f7c4SRyan Goodfellow 			if (makeflags[i] == 's') {
1115c3d5f7c4SRyan Goodfellow 				ctx->i_flags &= ~CW_F_ECHO;
1116c3d5f7c4SRyan Goodfellow 				break;
1117c3d5f7c4SRyan Goodfellow 			}
1118c3d5f7c4SRyan Goodfellow 			/* end of short flags */
1119c3d5f7c4SRyan Goodfellow 			if (makeflags[i] == ' ')
1120c3d5f7c4SRyan Goodfellow 				break;
1121c3d5f7c4SRyan Goodfellow 		}
1122c3d5f7c4SRyan Goodfellow 	}
1123c3d5f7c4SRyan Goodfellow 
112480ab886dSwesolows 	if (ctx->i_flags & CW_F_ECHO)
112580ab886dSwesolows 		(void) fprintf(stderr, "+ ");
112680ab886dSwesolows 
112780ab886dSwesolows 	for (ac = 0, a = ctx->i_ae->ael_head; a; a = a->ae_next, ac++) {
112880ab886dSwesolows 		newargv[ac] = a->ae_arg;
112980ab886dSwesolows 		if (ctx->i_flags & CW_F_ECHO)
113080ab886dSwesolows 			(void) fprintf(stderr, "%s ", a->ae_arg);
113180ab886dSwesolows 		if (a == ctx->i_ae->ael_tail)
113280ab886dSwesolows 			break;
113380ab886dSwesolows 	}
113480ab886dSwesolows 
113580ab886dSwesolows 	if (ctx->i_flags & CW_F_ECHO) {
113680ab886dSwesolows 		(void) fprintf(stderr, "\n");
113780ab886dSwesolows 		(void) fflush(stderr);
113880ab886dSwesolows 	}
113980ab886dSwesolows 
114080ab886dSwesolows 	if (!(ctx->i_flags & CW_F_EXEC))
114180ab886dSwesolows 		return (0);
114280ab886dSwesolows 
11437c478bd9Sstevel@tonic-gate 	/*
1144aa9ef484SJohn Levon 	 * We must fix up the environment here so that the dependency files are
1145aa9ef484SJohn Levon 	 * not trampled by the shadow compiler. Also take care of GCC
1146aa9ef484SJohn Levon 	 * environment variables that will throw off gcc. This assumes a primary
1147aa9ef484SJohn Levon 	 * gcc.
11487c478bd9Sstevel@tonic-gate 	 */
114980ab886dSwesolows 	if ((ctx->i_flags & CW_F_SHADOW) &&
115080ab886dSwesolows 	    (unsetenv("SUNPRO_DEPENDENCIES") != 0 ||
1151aa9ef484SJohn Levon 	    unsetenv("DEPENDENCIES_OUTPUT") != 0 ||
1152aa9ef484SJohn Levon 	    unsetenv("GCC_ROOT") != 0)) {
115380ab886dSwesolows 		(void) fprintf(stderr, "error: environment setup failed: %s\n",
115480ab886dSwesolows 		    strerror(errno));
115580ab886dSwesolows 		return (-1);
115680ab886dSwesolows 	}
11577c478bd9Sstevel@tonic-gate 
115880ab886dSwesolows 	(void) execv(newargv[0], newargv);
1159aa9ef484SJohn Levon 	warn("couldn't run %s", newargv[0]);
11607c478bd9Sstevel@tonic-gate 
116180ab886dSwesolows 	return (-1);
116280ab886dSwesolows }
116380ab886dSwesolows 
116480ab886dSwesolows static int
reap(cw_ictx_t * ctx)116580ab886dSwesolows reap(cw_ictx_t *ctx)
116680ab886dSwesolows {
11671912d2c4Swesolows 	int status, ret = 0;
116880ab886dSwesolows 	char buf[1024];
116980ab886dSwesolows 	struct stat s;
117080ab886dSwesolows 
1171c3f177eaSPeter Dennis - Sustaining Engineer 	/*
1172c3f177eaSPeter Dennis - Sustaining Engineer 	 * Only wait for one specific child.
1173c3f177eaSPeter Dennis - Sustaining Engineer 	 */
1174c3f177eaSPeter Dennis - Sustaining Engineer 	if (ctx->i_pid <= 0)
1175c3f177eaSPeter Dennis - Sustaining Engineer 		return (-1);
1176c3f177eaSPeter Dennis - Sustaining Engineer 
117780ab886dSwesolows 	do {
1178c3f177eaSPeter Dennis - Sustaining Engineer 		if (waitpid(ctx->i_pid, &status, 0) < 0) {
1179aa9ef484SJohn Levon 			warn("cannot reap child");
1180c3f177eaSPeter Dennis - Sustaining Engineer 			return (-1);
1181c3f177eaSPeter Dennis - Sustaining Engineer 		}
11821912d2c4Swesolows 		if (status != 0) {
11831912d2c4Swesolows 			if (WIFSIGNALED(status)) {
11841912d2c4Swesolows 				ret = -WTERMSIG(status);
118580ab886dSwesolows 				break;
11861912d2c4Swesolows 			} else if (WIFEXITED(status)) {
11871912d2c4Swesolows 				ret = WEXITSTATUS(status);
118880ab886dSwesolows 				break;
118980ab886dSwesolows 			}
11907c478bd9Sstevel@tonic-gate 		}
11911912d2c4Swesolows 	} while (!WIFEXITED(status) && !WIFSIGNALED(status));
119280ab886dSwesolows 
11931912d2c4Swesolows 	if (stat(ctx->i_stderr, &s) < 0) {
1194aa9ef484SJohn Levon 		warn("stat failed on child cleanup");
119580ab886dSwesolows 		return (-1);
11967c478bd9Sstevel@tonic-gate 	}
119780ab886dSwesolows 	if (s.st_size != 0) {
11981912d2c4Swesolows 		FILE *f;
119980ab886dSwesolows 
12001912d2c4Swesolows 		if ((f = fopen(ctx->i_stderr, "r")) != NULL) {
12011912d2c4Swesolows 			while (fgets(buf, sizeof (buf), f))
12021912d2c4Swesolows 				(void) fprintf(stderr, "%s", buf);
12031912d2c4Swesolows 			(void) fflush(stderr);
12041912d2c4Swesolows 			(void) fclose(f);
12051912d2c4Swesolows 		}
120680ab886dSwesolows 	}
12071912d2c4Swesolows 	(void) unlink(ctx->i_stderr);
12081912d2c4Swesolows 	free(ctx->i_stderr);
12091912d2c4Swesolows 
12101912d2c4Swesolows 	/*
12111912d2c4Swesolows 	 * cc returns an error code when given -V; we want that to succeed.
12121912d2c4Swesolows 	 */
12131912d2c4Swesolows 	if (ctx->i_flags & CW_F_PROG)
12141912d2c4Swesolows 		return (0);
121580ab886dSwesolows 
121680ab886dSwesolows 	return (ret);
121780ab886dSwesolows }
121880ab886dSwesolows 
121980ab886dSwesolows static int
exec_ctx(cw_ictx_t * ctx,int block)122080ab886dSwesolows exec_ctx(cw_ictx_t *ctx, int block)
122180ab886dSwesolows {
122288e61e85SRichard Lowe 	if ((ctx->i_stderr = tempnam(ctx->i_tmpdir, "cw")) == NULL) {
12231912d2c4Swesolows 		nomem();
122480ab886dSwesolows 		return (-1);
122580ab886dSwesolows 	}
122680ab886dSwesolows 
122780ab886dSwesolows 	if ((ctx->i_pid = fork()) == 0) {
12281912d2c4Swesolows 		int fd;
12291912d2c4Swesolows 
123080ab886dSwesolows 		(void) fclose(stderr);
12311912d2c4Swesolows 		if ((fd = open(ctx->i_stderr, O_WRONLY | O_CREAT | O_EXCL,
12321912d2c4Swesolows 		    0666)) < 0) {
1233aa9ef484SJohn Levon 			err(1, "open failed for standard error");
12341912d2c4Swesolows 		}
12351912d2c4Swesolows 		if (dup2(fd, 2) < 0) {
1236aa9ef484SJohn Levon 			err(1, "dup2 failed for standard error");
123780ab886dSwesolows 		}
12381912d2c4Swesolows 		if (fd != 2)
12391912d2c4Swesolows 			(void) close(fd);
124080ab886dSwesolows 		if (freopen("/dev/fd/2", "w", stderr) == NULL) {
1241aa9ef484SJohn Levon 			err(1, "freopen failed for /dev/fd/2");
124280ab886dSwesolows 		}
1243aa9ef484SJohn Levon 
124480ab886dSwesolows 		prepctx(ctx);
124580ab886dSwesolows 		exit(invoke(ctx));
124680ab886dSwesolows 	}
124780ab886dSwesolows 
124880ab886dSwesolows 	if (ctx->i_pid < 0) {
1249aa9ef484SJohn Levon 		err(1, "fork failed");
125080ab886dSwesolows 	}
125180ab886dSwesolows 
125280ab886dSwesolows 	if (block)
125380ab886dSwesolows 		return (reap(ctx));
125480ab886dSwesolows 
125580ab886dSwesolows 	return (0);
12567c478bd9Sstevel@tonic-gate }
12577c478bd9Sstevel@tonic-gate 
1258aa9ef484SJohn Levon static void
parse_compiler(const char * spec,cw_compiler_t * compiler)1259aa9ef484SJohn Levon parse_compiler(const char *spec, cw_compiler_t *compiler)
12607c478bd9Sstevel@tonic-gate {
1261aa9ef484SJohn Levon 	char *tspec, *token;
12627c478bd9Sstevel@tonic-gate 
1263aa9ef484SJohn Levon 	if ((tspec = strdup(spec)) == NULL)
126480ab886dSwesolows 		nomem();
126580ab886dSwesolows 
1266aa9ef484SJohn Levon 	if ((token = strsep(&tspec, ",")) == NULL)
1267aa9ef484SJohn Levon 		errx(1, "Compiler is missing a name: %s", spec);
1268aa9ef484SJohn Levon 	compiler->c_name = token;
12697c478bd9Sstevel@tonic-gate 
1270aa9ef484SJohn Levon 	if ((token = strsep(&tspec, ",")) == NULL)
1271aa9ef484SJohn Levon 		errx(1, "Compiler is missing a path: %s", spec);
1272aa9ef484SJohn Levon 	compiler->c_path = token;
12737c478bd9Sstevel@tonic-gate 
1274aa9ef484SJohn Levon 	if ((token = strsep(&tspec, ",")) == NULL)
1275aa9ef484SJohn Levon 		errx(1, "Compiler is missing a style: %s", spec);
12767c478bd9Sstevel@tonic-gate 
1277aa9ef484SJohn Levon 	if ((strcasecmp(token, "gnu") == 0) ||
12781f5207b7SJohn Levon 	    (strcasecmp(token, "gcc") == 0)) {
1279aa9ef484SJohn Levon 		compiler->c_style = GNU;
12801f5207b7SJohn Levon 	} else if ((strcasecmp(token, "sun") == 0) ||
12811f5207b7SJohn Levon 	    (strcasecmp(token, "cc") == 0)) {
1282aa9ef484SJohn Levon 		compiler->c_style = SUN;
12831f5207b7SJohn Levon 	} else if ((strcasecmp(token, "smatch") == 0)) {
12841f5207b7SJohn Levon 		compiler->c_style = SMATCH;
12851f5207b7SJohn Levon 	} else {
1286aa9ef484SJohn Levon 		errx(1, "unknown compiler style: %s", token);
12871f5207b7SJohn Levon 	}
128880ab886dSwesolows 
1289aa9ef484SJohn Levon 	if (tspec != NULL)
1290aa9ef484SJohn Levon 		errx(1, "Excess tokens in compiler: %s", spec);
1291aa9ef484SJohn Levon }
12927c478bd9Sstevel@tonic-gate 
129388e61e85SRichard Lowe static void
cleanup(cw_ictx_t * ctx)129488e61e85SRichard Lowe cleanup(cw_ictx_t *ctx)
129588e61e85SRichard Lowe {
129688e61e85SRichard Lowe 	DIR *dirp;
129788e61e85SRichard Lowe 	struct dirent *dp;
129888e61e85SRichard Lowe 	char buf[MAXPATHLEN];
129988e61e85SRichard Lowe 
130088e61e85SRichard Lowe 	if ((dirp = opendir(ctx->i_tmpdir)) == NULL) {
130188e61e85SRichard Lowe 		if (errno != ENOENT) {
130288e61e85SRichard Lowe 			err(1, "couldn't open temp directory: %s",
130388e61e85SRichard Lowe 			    ctx->i_tmpdir);
130488e61e85SRichard Lowe 		} else {
130588e61e85SRichard Lowe 			return;
130688e61e85SRichard Lowe 		}
130788e61e85SRichard Lowe 	}
130888e61e85SRichard Lowe 
130988e61e85SRichard Lowe 	errno = 0;
131088e61e85SRichard Lowe 	while ((dp = readdir(dirp)) != NULL) {
131188e61e85SRichard Lowe 		(void) snprintf(buf, MAXPATHLEN, "%s/%s", ctx->i_tmpdir,
131288e61e85SRichard Lowe 		    dp->d_name);
131388e61e85SRichard Lowe 
131488e61e85SRichard Lowe 		if (strcmp(dp->d_name, ".") == 0 ||
131588e61e85SRichard Lowe 		    strcmp(dp->d_name, "..") == 0) {
131688e61e85SRichard Lowe 			continue;
131788e61e85SRichard Lowe 		}
131888e61e85SRichard Lowe 
131988e61e85SRichard Lowe 		if (unlink(buf) == -1)
132088e61e85SRichard Lowe 			err(1, "failed to unlink temp file: %s", dp->d_name);
132188e61e85SRichard Lowe 		errno = 0;
132288e61e85SRichard Lowe 	}
132388e61e85SRichard Lowe 
132488e61e85SRichard Lowe 	if (errno != 0) {
132588e61e85SRichard Lowe 		err(1, "failed to read temporary directory: %s",
132688e61e85SRichard Lowe 		    ctx->i_tmpdir);
132788e61e85SRichard Lowe 	}
132888e61e85SRichard Lowe 
132988e61e85SRichard Lowe 	(void) closedir(dirp);
133088e61e85SRichard Lowe 	if (rmdir(ctx->i_tmpdir) != 0) {
133188e61e85SRichard Lowe 		err(1, "failed to unlink temporary directory: %s",
133288e61e85SRichard Lowe 		    ctx->i_tmpdir);
133388e61e85SRichard Lowe 	}
133488e61e85SRichard Lowe }
133588e61e85SRichard Lowe 
1336aa9ef484SJohn Levon int
main(int argc,char ** argv)1337aa9ef484SJohn Levon main(int argc, char **argv)
1338aa9ef484SJohn Levon {
1339aa9ef484SJohn Levon 	int ch;
1340aa9ef484SJohn Levon 	cw_compiler_t primary = { NULL, NULL, 0 };
1341aa9ef484SJohn Levon 	cw_compiler_t shadows[10];
1342aa9ef484SJohn Levon 	int nshadows = 0;
1343aa9ef484SJohn Levon 	int ret = 0;
134422a8b493SToomas Soome 	bool do_serial;
134522a8b493SToomas Soome 	bool do_exec;
134622a8b493SToomas Soome 	bool vflg = false;
134722a8b493SToomas Soome 	bool Cflg = false;
134822a8b493SToomas Soome 	bool cflg = false;
134922a8b493SToomas Soome 	bool nflg = false;
135088e61e85SRichard Lowe 	char *tmpdir;
1351aa9ef484SJohn Levon 
1352aa9ef484SJohn Levon 	cw_ictx_t *main_ctx;
1353aa9ef484SJohn Levon 
1354aa9ef484SJohn Levon 	static struct option longopts[] = {
1355aa9ef484SJohn Levon 		{ "compiler", no_argument, NULL, 'c' },
135669b1fd3fSRichard Lowe 		{ "linker", required_argument, NULL, 'l' },
1357aa9ef484SJohn Levon 		{ "noecho", no_argument, NULL, 'n' },
1358aa9ef484SJohn Levon 		{ "primary", required_argument, NULL, 'p' },
1359aa9ef484SJohn Levon 		{ "shadow", required_argument, NULL, 's' },
1360aa9ef484SJohn Levon 		{ "versions", no_argument, NULL, 'v' },
1361aa9ef484SJohn Levon 		{ NULL, 0, NULL, 0 },
1362aa9ef484SJohn Levon 	};
1363aa9ef484SJohn Levon 
1364aa9ef484SJohn Levon 
1365aa9ef484SJohn Levon 	if ((main_ctx = newictx()) == NULL)
1366aa9ef484SJohn Levon 		nomem();
1367aa9ef484SJohn Levon 
1368aa9ef484SJohn Levon 	while ((ch = getopt_long(argc, argv, "C", longopts, NULL)) != -1) {
1369aa9ef484SJohn Levon 		switch (ch) {
1370aa9ef484SJohn Levon 		case 'c':
137122a8b493SToomas Soome 			cflg = true;
1372aa9ef484SJohn Levon 			break;
1373aa9ef484SJohn Levon 		case 'C':
137422a8b493SToomas Soome 			Cflg = true;
1375aa9ef484SJohn Levon 			break;
137669b1fd3fSRichard Lowe 		case 'l':
137769b1fd3fSRichard Lowe 			if ((main_ctx->i_linker = strdup(optarg)) == NULL)
137869b1fd3fSRichard Lowe 				nomem();
137969b1fd3fSRichard Lowe 			break;
1380aa9ef484SJohn Levon 		case 'n':
138122a8b493SToomas Soome 			nflg = true;
1382aa9ef484SJohn Levon 			break;
1383aa9ef484SJohn Levon 		case 'p':
1384aa9ef484SJohn Levon 			if (primary.c_path != NULL) {
1385aa9ef484SJohn Levon 				warnx("Only one primary compiler may "
1386aa9ef484SJohn Levon 				    "be specified");
1387aa9ef484SJohn Levon 				usage();
1388aa9ef484SJohn Levon 			}
1389aa9ef484SJohn Levon 
1390aa9ef484SJohn Levon 			parse_compiler(optarg, &primary);
1391aa9ef484SJohn Levon 			break;
1392aa9ef484SJohn Levon 		case 's':
1393aa9ef484SJohn Levon 			if (nshadows >= 10)
1394aa9ef484SJohn Levon 				errx(1, "May only use 10 shadows at "
1395aa9ef484SJohn Levon 				    "the moment");
1396aa9ef484SJohn Levon 			parse_compiler(optarg, &shadows[nshadows]);
1397aa9ef484SJohn Levon 			nshadows++;
1398aa9ef484SJohn Levon 			break;
1399aa9ef484SJohn Levon 		case 'v':
140022a8b493SToomas Soome 			vflg = true;
1401aa9ef484SJohn Levon 			break;
1402aa9ef484SJohn Levon 		default:
1403aa9ef484SJohn Levon 			(void) fprintf(stderr, "Did you forget '--'?\n");
1404aa9ef484SJohn Levon 			usage();
1405aa9ef484SJohn Levon 		}
1406aa9ef484SJohn Levon 	}
1407aa9ef484SJohn Levon 
1408aa9ef484SJohn Levon 	if (primary.c_path == NULL) {
1409aa9ef484SJohn Levon 		warnx("A primary compiler must be specified");
14107c478bd9Sstevel@tonic-gate 		usage();
14117c478bd9Sstevel@tonic-gate 	}
14127c478bd9Sstevel@tonic-gate 
141322a8b493SToomas Soome 	do_serial = getenv("CW_SHADOW_SERIAL") != NULL;
141422a8b493SToomas Soome 	do_exec = getenv("CW_NO_EXEC") == NULL;
1415aa9ef484SJohn Levon 
1416aa9ef484SJohn Levon 	/* Leave room for argv[0] */
1417aa9ef484SJohn Levon 	argc -= (optind - 1);
1418aa9ef484SJohn Levon 	argv += (optind - 1);
1419aa9ef484SJohn Levon 
1420aa9ef484SJohn Levon 	main_ctx->i_oldargc = argc;
1421aa9ef484SJohn Levon 	main_ctx->i_oldargv = argv;
1422aa9ef484SJohn Levon 	main_ctx->i_flags = CW_F_XLATE;
1423aa9ef484SJohn Levon 	if (nflg == 0)
1424aa9ef484SJohn Levon 		main_ctx->i_flags |= CW_F_ECHO;
1425aa9ef484SJohn Levon 	if (do_exec)
1426aa9ef484SJohn Levon 		main_ctx->i_flags |= CW_F_EXEC;
1427aa9ef484SJohn Levon 	if (Cflg)
1428aa9ef484SJohn Levon 		main_ctx->i_flags |= CW_F_CXX;
1429aa9ef484SJohn Levon 	main_ctx->i_compiler = &primary;
1430aa9ef484SJohn Levon 
1431aa9ef484SJohn Levon 	if (cflg) {
1432aa9ef484SJohn Levon 		(void) fputs(primary.c_path, stdout);
14337c478bd9Sstevel@tonic-gate 	}
14347c478bd9Sstevel@tonic-gate 
1435aa9ef484SJohn Levon 	if (vflg) {
1436aa9ef484SJohn Levon 		(void) printf("cw version %s\n", CW_VERSION);
14371912d2c4Swesolows 		(void) fflush(stdout);
1438aa9ef484SJohn Levon 		main_ctx->i_flags &= ~CW_F_ECHO;
1439aa9ef484SJohn Levon 		main_ctx->i_flags |= CW_F_PROG | CW_F_EXEC;
14401912d2c4Swesolows 		do_serial = 1;
14411912d2c4Swesolows 	}
14421912d2c4Swesolows 
144388e61e85SRichard Lowe 	tmpdir = getenv("TMPDIR");
144488e61e85SRichard Lowe 	if (tmpdir == NULL)
144588e61e85SRichard Lowe 		tmpdir = "/tmp";
144688e61e85SRichard Lowe 
144788e61e85SRichard Lowe 	if (asprintf(&main_ctx->i_tmpdir, "%s/cw.XXXXXX", tmpdir) == -1)
144888e61e85SRichard Lowe 		nomem();
144988e61e85SRichard Lowe 
145088e61e85SRichard Lowe 	if ((main_ctx->i_tmpdir = mkdtemp(main_ctx->i_tmpdir)) == NULL)
145188e61e85SRichard Lowe 		errx(1, "failed to create temporary directory");
145288e61e85SRichard Lowe 
1453aa9ef484SJohn Levon 	ret |= exec_ctx(main_ctx, do_serial);
14541912d2c4Swesolows 
1455aa9ef484SJohn Levon 	for (int i = 0; i < nshadows; i++) {
1456aa9ef484SJohn Levon 		int r;
1457aa9ef484SJohn Levon 		cw_ictx_t *shadow_ctx;
145880ab886dSwesolows 
1459aa9ef484SJohn Levon 		if ((shadow_ctx = newictx()) == NULL)
1460aa9ef484SJohn Levon 			nomem();
1461aa9ef484SJohn Levon 
146288e61e85SRichard Lowe 		(void) memcpy(shadow_ctx, main_ctx, sizeof (cw_ictx_t));
1463aa9ef484SJohn Levon 
1464aa9ef484SJohn Levon 		shadow_ctx->i_flags |= CW_F_SHADOW;
1465aa9ef484SJohn Levon 		shadow_ctx->i_compiler = &shadows[i];
1466aa9ef484SJohn Levon 
1467aa9ef484SJohn Levon 		r = exec_ctx(shadow_ctx, do_serial);
1468aa9ef484SJohn Levon 		if (r == 0) {
1469aa9ef484SJohn Levon 			shadow_ctx->i_next = main_ctx->i_next;
1470aa9ef484SJohn Levon 			main_ctx->i_next = shadow_ctx;
1471aa9ef484SJohn Levon 		}
1472aa9ef484SJohn Levon 		ret |= r;
14737c478bd9Sstevel@tonic-gate 	}
14747c478bd9Sstevel@tonic-gate 
1475aa9ef484SJohn Levon 	if (!do_serial) {
1476aa9ef484SJohn Levon 		cw_ictx_t *next = main_ctx;
1477aa9ef484SJohn Levon 		while (next != NULL) {
1478aa9ef484SJohn Levon 			cw_ictx_t *toreap = next;
1479aa9ef484SJohn Levon 			next = next->i_next;
1480aa9ef484SJohn Levon 			ret |= reap(toreap);
1481aa9ef484SJohn Levon 		}
1482aa9ef484SJohn Levon 	}
14837c478bd9Sstevel@tonic-gate 
148488e61e85SRichard Lowe 	cleanup(main_ctx);
148580ab886dSwesolows 	return (ret);
14867c478bd9Sstevel@tonic-gate }
1487