xref: /openbsd-src/usr.sbin/crunchgen/crunchgen.c (revision ea00e92bee67cd09972e11daf60dc1b5ce17766d)
1*ea00e92bSderaadt /* $OpenBSD: crunchgen.c,v 1.30 2024/06/02 18:47:17 deraadt Exp $	 */
2cbf5262eSderaadt 
3cbf5262eSderaadt /*
4cbf5262eSderaadt  * Copyright (c) 1994 University of Maryland
5cbf5262eSderaadt  * All Rights Reserved.
6cbf5262eSderaadt  *
7cbf5262eSderaadt  * Permission to use, copy, modify, distribute, and sell this software and its
8cbf5262eSderaadt  * documentation for any purpose is hereby granted without fee, provided that
9cbf5262eSderaadt  * the above copyright notice appear in all copies and that both that
10cbf5262eSderaadt  * copyright notice and this permission notice appear in supporting
11cbf5262eSderaadt  * documentation, and that the name of U.M. not be used in advertising or
12cbf5262eSderaadt  * publicity pertaining to distribution of the software without specific,
13cbf5262eSderaadt  * written prior permission.  U.M. makes no representations about the
14cbf5262eSderaadt  * suitability of this software for any purpose.  It is provided "as is"
15cbf5262eSderaadt  * without express or implied warranty.
16cbf5262eSderaadt  *
17cbf5262eSderaadt  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18cbf5262eSderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19cbf5262eSderaadt  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20cbf5262eSderaadt  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21cbf5262eSderaadt  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22cbf5262eSderaadt  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23cbf5262eSderaadt  *
24cbf5262eSderaadt  * Author: James da Silva, Systems Design and Analysis Group
25cbf5262eSderaadt  *			   Computer Science Department
26cbf5262eSderaadt  *			   University of Maryland at College Park
27cbf5262eSderaadt  */
28cbf5262eSderaadt /*
29cbf5262eSderaadt  * ========================================================================
30cbf5262eSderaadt  * crunchgen.c
31cbf5262eSderaadt  *
32cbf5262eSderaadt  * Generates a Makefile and main C file for a crunched executable,
33cbf5262eSderaadt  * from specs given in a .conf file.
34cbf5262eSderaadt  */
35b9fc9a72Sderaadt #include <sys/param.h>	/* MACHINE */
36b9fc9a72Sderaadt #include <sys/types.h>
37b9fc9a72Sderaadt #include <sys/stat.h>
38b9fc9a72Sderaadt 
39cbf5262eSderaadt #include <stdio.h>
40cbf5262eSderaadt #include <stdlib.h>
41cbf5262eSderaadt #include <unistd.h>
42cbf5262eSderaadt #include <ctype.h>
43cbf5262eSderaadt #include <string.h>
44b9fc9a72Sderaadt #include <limits.h>
4581b62b13Shenning #include <fcntl.h>
4681b62b13Shenning #include <libgen.h>
47cbf5262eSderaadt 
48a66c1913Sderaadt #define CRUNCH_VERSION	"1.3"
49cbf5262eSderaadt 
50cbf5262eSderaadt #define MAXLINELEN	16384
51cbf5262eSderaadt #define MAXFIELDS 	 2048
52cbf5262eSderaadt 
53cbf5262eSderaadt /* XXX - This should be runtime configurable */
54cbf5262eSderaadt /*
55cbf5262eSderaadt  * We might have more than one makefile
56cbf5262eSderaadt  * name on any given platform. Make sure
57cbf5262eSderaadt  * default name is last though.
58cbf5262eSderaadt  */
59cbf5262eSderaadt char	*mf_name[] = {
60cbf5262eSderaadt 	"Makefile.bsd-wrapper",
61cbf5262eSderaadt 	"Makefile",
62cbf5262eSderaadt 	NULL
63cbf5262eSderaadt };
64cbf5262eSderaadt 
65cbf5262eSderaadt /* internal representation of conf file: */
66cbf5262eSderaadt 
67cbf5262eSderaadt /* simple lists of strings suffice for most parms */
68cbf5262eSderaadt 
69cbf5262eSderaadt typedef struct strlst {
70cbf5262eSderaadt 	struct strlst  *next;
71cbf5262eSderaadt 	char           *str;
72cbf5262eSderaadt } strlst_t;
73cbf5262eSderaadt 
74cbf5262eSderaadt /* progs have structure, each field can be set with "special" or calculated */
75cbf5262eSderaadt 
76cbf5262eSderaadt typedef struct prog {
77cbf5262eSderaadt 	struct prog    *next;
78cbf5262eSderaadt 	char           *name, *ident, *mf_name;
79cbf5262eSderaadt 	char           *srcdir, *objdir;
80cbf5262eSderaadt 	strlst_t       *objs, *objpaths;
81cbf5262eSderaadt 	strlst_t       *links;
82cbf5262eSderaadt 	int             goterror;
83cbf5262eSderaadt } prog_t;
84cbf5262eSderaadt 
85cbf5262eSderaadt strlst_t       *srcdirs = NULL;
86cbf5262eSderaadt strlst_t       *libs = NULL;
87cbf5262eSderaadt strlst_t       *libdirs = NULL;
88b9fc9a72Sderaadt char		objdir[PATH_MAX] = "obj";
89cbf5262eSderaadt prog_t         *progs = NULL;
90cbf5262eSderaadt 
91cbf5262eSderaadt char            line[MAXLINELEN];
92cbf5262eSderaadt 
93b9fc9a72Sderaadt char            confname[PATH_MAX], infilename[PATH_MAX];
94b9fc9a72Sderaadt char            outmkname[PATH_MAX], outcfname[PATH_MAX];
95b9fc9a72Sderaadt char            cachename[PATH_MAX], curfilename[PATH_MAX];
96b9fc9a72Sderaadt char            topdir[PATH_MAX], execfname[PATH_MAX];
97cbf5262eSderaadt int             linenum = -1;
98cbf5262eSderaadt int             goterror = 0;
99cbf5262eSderaadt 
10090d4c299Sderaadt extern char	*__progname;
101cbf5262eSderaadt 
10203ab18c2Sdrahn int             verbose = 1, readcache = 1, elf_names, elf_mangle; /* options */
103cbf5262eSderaadt int             reading_cache;
104cbf5262eSderaadt 
105cbf5262eSderaadt void            out_of_memory(void);
106cbf5262eSderaadt void            add_string(strlst_t ** listp, char *str);
107cbf5262eSderaadt int             is_dir(char *pathname);
108cbf5262eSderaadt int             is_nonempty_file(char *pathname);
109cbf5262eSderaadt void            usage(void);
110cbf5262eSderaadt void            parse_conf_file(void);
111cbf5262eSderaadt void            gen_outputs(void);
112cbf5262eSderaadt 
113cbf5262eSderaadt extern int	crunchide_main(int, char *[]);
114cbf5262eSderaadt 
115cbf5262eSderaadt int
main(int argc,char * argv[])116cbf5262eSderaadt main(int argc, char *argv[])
117cbf5262eSderaadt {
118cbf5262eSderaadt 	char           *p;
119cbf5262eSderaadt 	int             optc;
120cbf5262eSderaadt 
1219b32031cSderaadt 	if (pledge("stdio rpath wpath cpath proc exec", NULL) == -1) {
1228b5c46d7Sderaadt 		perror("pledge");
1239b32031cSderaadt 		exit(1);
1249b32031cSderaadt 	}
1258b5c46d7Sderaadt 
12603ab18c2Sdrahn 	while ((optc = getopt(argc, argv, "hm:c:e:fqD:EL:O:M")) != -1) {
127cbf5262eSderaadt 		switch (optc) {
12890d4c299Sderaadt 		case 'h':
12990d4c299Sderaadt 			optreset = 1;
13090d4c299Sderaadt 			return (crunchide_main(argc, argv));
13190d4c299Sderaadt 			break;
132cbf5262eSderaadt 		case 'f':
133cbf5262eSderaadt 			readcache = 0;
134cbf5262eSderaadt 			break;
135cbf5262eSderaadt 		case 'q':
136cbf5262eSderaadt 			verbose = 0;
137cbf5262eSderaadt 			break;
138cbf5262eSderaadt 
139cbf5262eSderaadt 		case 'm':
140cbf5262eSderaadt 			if (strlcpy(outmkname, optarg, sizeof(outmkname)) >=
141cbf5262eSderaadt 			    sizeof(outmkname))
142cbf5262eSderaadt 				usage();
143cbf5262eSderaadt 			break;
144cbf5262eSderaadt 		case 'c':
145cbf5262eSderaadt 			if (strlcpy(outcfname, optarg, sizeof(outcfname)) >=
146cbf5262eSderaadt 			    sizeof(outcfname))
147cbf5262eSderaadt 				usage();
148cbf5262eSderaadt 			break;
149cbf5262eSderaadt 		case 'e':
150cbf5262eSderaadt 			if (strlcpy(execfname, optarg, sizeof(execfname)) >=
151cbf5262eSderaadt 			    sizeof(execfname))
152cbf5262eSderaadt 				usage();
153cbf5262eSderaadt 			break;
154cbf5262eSderaadt 
155cbf5262eSderaadt 		case 'D':
156cbf5262eSderaadt 			if (strlcpy(topdir, optarg, sizeof(topdir)) >= sizeof(topdir))
157cbf5262eSderaadt 				usage();
158cbf5262eSderaadt 			break;
159cbf5262eSderaadt 		case 'E':
160cbf5262eSderaadt 			elf_names = 1;
161cbf5262eSderaadt 			break;
162cbf5262eSderaadt 		case 'L':
163b9fc9a72Sderaadt 			if (strlen(optarg) >= PATH_MAX)
164cbf5262eSderaadt 				usage();
165cbf5262eSderaadt 			add_string(&libdirs, optarg);
166cbf5262eSderaadt 			break;
167cbf5262eSderaadt 		case 'O':
168cbf5262eSderaadt 			if (strlcpy(objdir, optarg, sizeof(objdir)) >=
169cbf5262eSderaadt 			    sizeof(objdir))
170cbf5262eSderaadt 				usage();
171cbf5262eSderaadt 			break;
17203ab18c2Sdrahn 		case 'M':
17303ab18c2Sdrahn 			elf_mangle = 1;
17403ab18c2Sdrahn 			break;
175cbf5262eSderaadt 		default:
176cbf5262eSderaadt 			usage();
177cbf5262eSderaadt 		}
178cbf5262eSderaadt 	}
179cbf5262eSderaadt 
180cbf5262eSderaadt 	argc -= optind;
181cbf5262eSderaadt 	argv += optind;
182cbf5262eSderaadt 
183cbf5262eSderaadt 	if (argc != 1)
184cbf5262eSderaadt 		usage();
185cbf5262eSderaadt 
186cbf5262eSderaadt 	if (libdirs == NULL)
187cbf5262eSderaadt 		add_string(&libdirs, "/usr/lib");
188cbf5262eSderaadt 	/*
189cbf5262eSderaadt          * generate filenames
190cbf5262eSderaadt          */
191cbf5262eSderaadt 
192cbf5262eSderaadt 	if (strlcpy(infilename, argv[0], sizeof(infilename)) >=
193cbf5262eSderaadt 	    sizeof(infilename))
194cbf5262eSderaadt 		usage();
195cbf5262eSderaadt 
196cbf5262eSderaadt 	/* confname = `basename infilename .conf` */
197cbf5262eSderaadt 
198cbf5262eSderaadt 	if ((p = strrchr(infilename, '/')) != NULL)
199cbf5262eSderaadt 		strlcpy(confname, p + 1, sizeof confname);
200cbf5262eSderaadt 	else
201cbf5262eSderaadt 		strlcpy(confname, infilename, sizeof confname);
202cbf5262eSderaadt 	if ((p = strrchr(confname, '.')) != NULL && !strcmp(p, ".conf"))
203cbf5262eSderaadt 		*p = '\0';
204cbf5262eSderaadt 
205cbf5262eSderaadt 	if (!*outmkname)
206cbf5262eSderaadt 		snprintf(outmkname, sizeof(outmkname), "%s.mk", confname);
207cbf5262eSderaadt 	if (!*outcfname)
208cbf5262eSderaadt 		snprintf(outcfname, sizeof(outcfname), "%s.c", confname);
209cbf5262eSderaadt 	if (!*execfname)
210cbf5262eSderaadt 		snprintf(execfname, sizeof(execfname), "%s", confname);
211cbf5262eSderaadt 	snprintf(cachename, sizeof(cachename), "%s.cache", confname);
212cbf5262eSderaadt 
213cbf5262eSderaadt 	parse_conf_file();
214cbf5262eSderaadt 	gen_outputs();
215cbf5262eSderaadt 
216cbf5262eSderaadt 	exit(goterror);
217cbf5262eSderaadt }
218cbf5262eSderaadt 
219cbf5262eSderaadt void
usage(void)220cbf5262eSderaadt usage(void)
221cbf5262eSderaadt {
222cbf5262eSderaadt 	fprintf(stderr,
22303ab18c2Sdrahn 	    "usage: crunchgen [-EfMq] [-c c-file-name] [-D src-root] [-e exec-file-name]\n"
22490d4c299Sderaadt 	    "\t[-L lib-dir] [-m makefile-name] [-O objdir-name] conf-file\n");
22590d4c299Sderaadt 	fprintf(stderr,
226516251d4Sdrahn 	    "       crunchgen -h [-M] [-f keep-list-file] [-k keep-symbol] object-file ...\n");
227cbf5262eSderaadt 	exit(1);
228cbf5262eSderaadt }
229cbf5262eSderaadt 
230cbf5262eSderaadt void            parse_one_file(char *filename);
231cbf5262eSderaadt void            parse_line(char *line, int *fc, char **fv, int nf);
232cbf5262eSderaadt void            add_srcdirs(int argc, char **argv);
233cbf5262eSderaadt void            add_progs(int argc, char **argv);
234cbf5262eSderaadt void            add_link(int argc, char **argv);
235cbf5262eSderaadt void            add_libs(int argc, char **argv);
236cbf5262eSderaadt void            add_libdirs(int argc, char **argv);
237cbf5262eSderaadt void            add_special(int argc, char **argv);
238cbf5262eSderaadt 
239cbf5262eSderaadt prog_t         *find_prog(char *str);
240cbf5262eSderaadt void            add_prog(char *progname);
241cbf5262eSderaadt 
242cbf5262eSderaadt void
parse_conf_file(void)243cbf5262eSderaadt parse_conf_file(void)
244cbf5262eSderaadt {
245cbf5262eSderaadt 	if (!is_nonempty_file(infilename)) {
246cbf5262eSderaadt 		fprintf(stderr, "%s: fatal: input file \"%s\" not found.\n",
24790d4c299Sderaadt 		    __progname, infilename);
248cbf5262eSderaadt 		exit(1);
249cbf5262eSderaadt 	}
250cbf5262eSderaadt 	parse_one_file(infilename);
251cbf5262eSderaadt 	if (readcache && is_nonempty_file(cachename)) {
252cbf5262eSderaadt 		reading_cache = 1;
253cbf5262eSderaadt 		parse_one_file(cachename);
254cbf5262eSderaadt 	}
255cbf5262eSderaadt }
256cbf5262eSderaadt 
257cbf5262eSderaadt void
parse_one_file(char * filename)258cbf5262eSderaadt parse_one_file(char *filename)
259cbf5262eSderaadt {
260cbf5262eSderaadt 	char           *fieldv[MAXFIELDS];
261cbf5262eSderaadt 	int             fieldc;
262cbf5262eSderaadt 	void            (*f) (int c, char **v);
263cbf5262eSderaadt 	FILE           *cf;
264cbf5262eSderaadt 
265cbf5262eSderaadt 	strlcpy(curfilename, filename, sizeof curfilename);
266cbf5262eSderaadt 
267cbf5262eSderaadt 	if ((cf = fopen(curfilename, "r")) == NULL) {
268cbf5262eSderaadt 		perror(curfilename);
269cbf5262eSderaadt 		goterror = 1;
270cbf5262eSderaadt 		return;
271cbf5262eSderaadt 	}
272cbf5262eSderaadt 	linenum = 0;
273cbf5262eSderaadt 	while (fgets(line, MAXLINELEN, cf) != NULL) {
274cbf5262eSderaadt 		linenum++;
275cbf5262eSderaadt 		parse_line(line, &fieldc, fieldv, MAXFIELDS);
276cbf5262eSderaadt 		if (fieldc < 1)
277cbf5262eSderaadt 			continue;
278cbf5262eSderaadt 		if (!strcmp(fieldv[0], "srcdirs"))
279cbf5262eSderaadt 			f = add_srcdirs;
280cbf5262eSderaadt 		else if (!strcmp(fieldv[0], "progs"))
281cbf5262eSderaadt 			f = add_progs;
282cbf5262eSderaadt 		else if (!strcmp(fieldv[0], "ln"))
283cbf5262eSderaadt 			f = add_link;
284cbf5262eSderaadt 		else if (!strcmp(fieldv[0], "libs"))
285cbf5262eSderaadt 			f = add_libs;
286cbf5262eSderaadt 		else if (!strcmp(fieldv[0], "special"))
287cbf5262eSderaadt 			f = add_special;
288cbf5262eSderaadt 		else if (!strcmp(fieldv[0], "libdirs"))
289cbf5262eSderaadt 			f = add_libdirs;
290cbf5262eSderaadt 		else {
291cbf5262eSderaadt 			fprintf(stderr, "%s:%d: skipping unknown command `%s'.\n",
292cbf5262eSderaadt 			    curfilename, linenum, fieldv[0]);
293cbf5262eSderaadt 			goterror = 1;
294cbf5262eSderaadt 			continue;
295cbf5262eSderaadt 		}
296cbf5262eSderaadt 		if (fieldc < 2) {
297cbf5262eSderaadt 			fprintf(stderr,
298cbf5262eSderaadt 			    "%s:%d: %s command needs at least 1 "
299cbf5262eSderaadt 		  	    "argument, skipping.\n",
300cbf5262eSderaadt 			    curfilename, linenum, fieldv[0]);
301cbf5262eSderaadt 			goterror = 1;
302cbf5262eSderaadt 			continue;
303cbf5262eSderaadt 		}
304cbf5262eSderaadt 		f(fieldc, fieldv);
305cbf5262eSderaadt 	}
306cbf5262eSderaadt 
307cbf5262eSderaadt 	if (ferror(cf)) {
308cbf5262eSderaadt 		perror(curfilename);
309cbf5262eSderaadt 		goterror = 1;
310cbf5262eSderaadt 	}
311cbf5262eSderaadt 	fclose(cf);
312cbf5262eSderaadt }
313cbf5262eSderaadt 
314cbf5262eSderaadt void
parse_line(char * line,int * fc,char ** fv,int nf)315cbf5262eSderaadt parse_line(char *line, int *fc, char **fv, int nf)
316cbf5262eSderaadt {
317cbf5262eSderaadt 	char           *p;
318cbf5262eSderaadt 
319cbf5262eSderaadt 	p = line;
320cbf5262eSderaadt 	*fc = 0;
321cbf5262eSderaadt 	while (1) {
322701d8205Sderaadt 		while (isspace((unsigned char)*p))
323cbf5262eSderaadt 			p++;
324cbf5262eSderaadt 		if (*p == '\0' || *p == '#')
325cbf5262eSderaadt 			break;
326cbf5262eSderaadt 
327cbf5262eSderaadt 		if (*fc < nf)
328cbf5262eSderaadt 			fv[(*fc)++] = p;
329701d8205Sderaadt 		while (*p && !isspace((unsigned char)*p) && *p != '#')
330cbf5262eSderaadt 			p++;
331cbf5262eSderaadt 		if (*p == '\0' || *p == '#')
332cbf5262eSderaadt 			break;
333cbf5262eSderaadt 		*p++ = '\0';
334cbf5262eSderaadt 	}
335cbf5262eSderaadt 	if (*p)
336cbf5262eSderaadt 		*p = '\0';	/* needed for '#' case */
337cbf5262eSderaadt }
338cbf5262eSderaadt 
339cbf5262eSderaadt void
add_srcdirs(int argc,char ** argv)340cbf5262eSderaadt add_srcdirs(int argc, char **argv)
341cbf5262eSderaadt {
342cbf5262eSderaadt 	int             i;
343b9fc9a72Sderaadt 	char            tmppath[PATH_MAX];
344cbf5262eSderaadt 	int             overflow;
345cbf5262eSderaadt 
346cbf5262eSderaadt 	for (i = 1; i < argc; i++) {
347cbf5262eSderaadt 		overflow = 0;
348cbf5262eSderaadt 		if (argv[i][0] == '/' || topdir[0] == '\0') {
349cbf5262eSderaadt 			if (strlcpy(tmppath, argv[i], sizeof(tmppath)) >=
350cbf5262eSderaadt 			    sizeof(tmppath))
351cbf5262eSderaadt 				overflow = 1;
352cbf5262eSderaadt 		} else {
353cbf5262eSderaadt 			if (strlcpy(tmppath, topdir, sizeof(tmppath)) >=
354cbf5262eSderaadt 			    sizeof(tmppath) ||
355cbf5262eSderaadt 			    strlcat(tmppath, "/", sizeof(tmppath)) >=
356cbf5262eSderaadt 			    sizeof(tmppath) ||
357cbf5262eSderaadt 			    strlcat(tmppath, argv[i], sizeof(tmppath)) >=
358cbf5262eSderaadt 			    sizeof(tmppath))
359cbf5262eSderaadt 				overflow = 1;
360cbf5262eSderaadt 		}
361cbf5262eSderaadt 		if (overflow) {
362cbf5262eSderaadt 			goterror = 1;
363cbf5262eSderaadt 			fprintf(stderr, "%s:%d: `%.40s...' is too long, skipping it.\n",
364cbf5262eSderaadt 			    curfilename, linenum, argv[i]);
365cbf5262eSderaadt 			continue;
366cbf5262eSderaadt 		}
367cbf5262eSderaadt 		if (is_dir(tmppath))
368cbf5262eSderaadt 			add_string(&srcdirs, tmppath);
369cbf5262eSderaadt 		else {
370cbf5262eSderaadt 			fprintf(stderr, "%s:%d: `%s' is not a directory, skipping it.\n",
371cbf5262eSderaadt 			    curfilename, linenum, tmppath);
372cbf5262eSderaadt 			goterror = 1;
373cbf5262eSderaadt 		}
374cbf5262eSderaadt 	}
375cbf5262eSderaadt }
376cbf5262eSderaadt 
377cbf5262eSderaadt void
add_libdirs(int argc,char ** argv)378cbf5262eSderaadt add_libdirs(int argc, char **argv)
379cbf5262eSderaadt {
380cbf5262eSderaadt 	int             i;
381b9fc9a72Sderaadt 	char            tmppath[PATH_MAX];
382b9fc9a72Sderaadt 	char            tmppath2[PATH_MAX];
383cbf5262eSderaadt 	int             overflow;
384cbf5262eSderaadt 
385cbf5262eSderaadt 	for (i = 1; i < argc; i++) {
386cbf5262eSderaadt 		overflow = 0;
387cbf5262eSderaadt 		if (argv[i][0] == '/' || topdir[0] == '\0') {
388cbf5262eSderaadt 			if (strlcpy(tmppath, argv[i], sizeof(tmppath)) >=
389cbf5262eSderaadt 			    sizeof(tmppath))
390cbf5262eSderaadt 				overflow = 1;
391cbf5262eSderaadt 		} else {
392cbf5262eSderaadt 			if (strlcpy(tmppath, topdir, sizeof(tmppath)) >=
393cbf5262eSderaadt 			    sizeof(tmppath) ||
394cbf5262eSderaadt 			    strlcat(tmppath, "/", sizeof(tmppath)) >=
395cbf5262eSderaadt 			    sizeof(tmppath) ||
396cbf5262eSderaadt 			    strlcat(tmppath, argv[i], sizeof(tmppath)) >=
397cbf5262eSderaadt 			    sizeof(tmppath))
398cbf5262eSderaadt 				overflow = 1;
399cbf5262eSderaadt 		}
400cbf5262eSderaadt 		if (overflow) {
401cbf5262eSderaadt 			goterror = 1;
402cbf5262eSderaadt 			fprintf(stderr, "%s:%d: `%.40s...' is too long, skipping it.\n",
403cbf5262eSderaadt 			    curfilename, linenum, argv[i]);
404cbf5262eSderaadt 			continue;
405cbf5262eSderaadt 		}
406cbf5262eSderaadt 		if (is_dir(tmppath)) {
407cbf5262eSderaadt 			snprintf(tmppath2, sizeof(tmppath2), "%s/%s", tmppath,
408cbf5262eSderaadt 			    objdir);
409cbf5262eSderaadt 			if (is_dir(tmppath2))
410cbf5262eSderaadt 				add_string(&libdirs, tmppath2);
411cbf5262eSderaadt 			else {
412cbf5262eSderaadt 				snprintf(tmppath2, sizeof(tmppath2),
413cbf5262eSderaadt 				    "%s/obj.%s", tmppath, MACHINE);
414cbf5262eSderaadt 				if (is_dir(tmppath2))
415cbf5262eSderaadt 					add_string(&libdirs, tmppath2);
416cbf5262eSderaadt 				else
417cbf5262eSderaadt 					add_string(&libdirs, tmppath);
418cbf5262eSderaadt 			}
419cbf5262eSderaadt 		}
420cbf5262eSderaadt 		else {
421cbf5262eSderaadt 			fprintf(stderr, "%s:%d: `%s' is not a directory, skipping it.\n",
422cbf5262eSderaadt 			    curfilename, linenum, tmppath);
423cbf5262eSderaadt 			goterror = 1;
424cbf5262eSderaadt 		}
425cbf5262eSderaadt 	}
426cbf5262eSderaadt }
427cbf5262eSderaadt 
428cbf5262eSderaadt 
429cbf5262eSderaadt void
add_progs(int argc,char ** argv)430cbf5262eSderaadt add_progs(int argc, char **argv)
431cbf5262eSderaadt {
432cbf5262eSderaadt 	int             i;
433cbf5262eSderaadt 
434cbf5262eSderaadt 	for (i = 1; i < argc; i++)
435cbf5262eSderaadt 		add_prog(argv[i]);
436cbf5262eSderaadt }
437cbf5262eSderaadt 
438cbf5262eSderaadt void
add_prog(char * progname)439cbf5262eSderaadt add_prog(char *progname)
440cbf5262eSderaadt {
441cbf5262eSderaadt 	prog_t         *p1, *p2;
442cbf5262eSderaadt 
443cbf5262eSderaadt 	/* add to end, but be smart about dups */
444cbf5262eSderaadt 
445cbf5262eSderaadt 	for (p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next)
446cbf5262eSderaadt 		if (!strcmp(p2->name, progname))
447cbf5262eSderaadt 			return;
448cbf5262eSderaadt 
449cbf5262eSderaadt 	p2 = calloc(1, sizeof(prog_t));
450cbf5262eSderaadt 	if (p2)
451cbf5262eSderaadt 		p2->name = strdup(progname);
452cbf5262eSderaadt 	if (!p2 || !p2->name)
453cbf5262eSderaadt 		out_of_memory();
454cbf5262eSderaadt 
455cbf5262eSderaadt 	p2->next = NULL;
456cbf5262eSderaadt 	if (p1 == NULL)
457cbf5262eSderaadt 		progs = p2;
458cbf5262eSderaadt 	else
459cbf5262eSderaadt 		p1->next = p2;
460cbf5262eSderaadt 
461cbf5262eSderaadt 	p2->ident = p2->srcdir = p2->objdir = NULL;
462cbf5262eSderaadt 	p2->links = p2->objs = NULL;
463cbf5262eSderaadt 	p2->goterror = 0;
464cbf5262eSderaadt }
465cbf5262eSderaadt 
466cbf5262eSderaadt void
add_link(int argc,char ** argv)467cbf5262eSderaadt add_link(int argc, char **argv)
468cbf5262eSderaadt {
469cbf5262eSderaadt 	int             i;
470cbf5262eSderaadt 	prog_t         *p = find_prog(argv[1]);
471cbf5262eSderaadt 
472cbf5262eSderaadt 	if (p == NULL) {
473cbf5262eSderaadt 		fprintf(stderr,
474cbf5262eSderaadt 		    "%s:%d: no prog %s previously declared, skipping link.\n",
475cbf5262eSderaadt 		    curfilename, linenum, argv[1]);
476cbf5262eSderaadt 		goterror = 1;
477cbf5262eSderaadt 		return;
478cbf5262eSderaadt 	}
479cbf5262eSderaadt 	for (i = 2; i < argc; i++)
480cbf5262eSderaadt 		add_string(&p->links, argv[i]);
481cbf5262eSderaadt }
482cbf5262eSderaadt 
483cbf5262eSderaadt void
add_libs(int argc,char ** argv)484cbf5262eSderaadt add_libs(int argc, char **argv)
485cbf5262eSderaadt {
486cbf5262eSderaadt 	int             i;
487cbf5262eSderaadt 
488cbf5262eSderaadt 	for (i = 1; i < argc; i++)
489cbf5262eSderaadt 		add_string(&libs, argv[i]);
490cbf5262eSderaadt }
491cbf5262eSderaadt 
492cbf5262eSderaadt void
add_special(int argc,char ** argv)493cbf5262eSderaadt add_special(int argc, char **argv)
494cbf5262eSderaadt {
495cbf5262eSderaadt 	int             i;
496cbf5262eSderaadt 	prog_t         *p = find_prog(argv[1]);
497cbf5262eSderaadt 
498cbf5262eSderaadt 	if (p == NULL) {
499cbf5262eSderaadt 		if (reading_cache)
500cbf5262eSderaadt 			return;
501cbf5262eSderaadt 		fprintf(stderr,
502cbf5262eSderaadt 		    "%s:%d: no prog %s previously declared, skipping special.\n",
503cbf5262eSderaadt 		    curfilename, linenum, argv[1]);
504cbf5262eSderaadt 		goterror = 1;
505cbf5262eSderaadt 		return;
506cbf5262eSderaadt 	}
507cbf5262eSderaadt 	if (!strcmp(argv[2], "ident")) {
508cbf5262eSderaadt 		if (argc != 4)
509cbf5262eSderaadt 			goto argcount;
510cbf5262eSderaadt 		if ((p->ident = strdup(argv[3])) == NULL)
511cbf5262eSderaadt 			out_of_memory();
512cbf5262eSderaadt 	} else if (!strcmp(argv[2], "srcdir")) {
513cbf5262eSderaadt 		if (argc != 4)
514cbf5262eSderaadt 			goto argcount;
515cbf5262eSderaadt 		if ((p->srcdir = strdup(argv[3])) == NULL)
516cbf5262eSderaadt 			out_of_memory();
517cbf5262eSderaadt 	} else if (!strcmp(argv[2], "mf_name")) {
518cbf5262eSderaadt 		if (argc != 4)
519cbf5262eSderaadt 			goto argcount;
520cbf5262eSderaadt 		if ((p->mf_name = strdup(argv[3])) == NULL)
521cbf5262eSderaadt 			out_of_memory();
522cbf5262eSderaadt 	} else if (!strcmp(argv[2], "objdir")) {
523cbf5262eSderaadt 		if (argc != 4)
524cbf5262eSderaadt 			goto argcount;
525cbf5262eSderaadt 		if ((p->objdir = strdup(argv[3])) == NULL)
526cbf5262eSderaadt 			out_of_memory();
527cbf5262eSderaadt 	} else if (!strcmp(argv[2], "objs")) {
528cbf5262eSderaadt 		p->objs = NULL;
529cbf5262eSderaadt 		for (i = 3; i < argc; i++)
530cbf5262eSderaadt 			add_string(&p->objs, argv[i]);
531cbf5262eSderaadt 	} else if (!strcmp(argv[2], "objpaths")) {
532cbf5262eSderaadt 		p->objpaths = NULL;
533cbf5262eSderaadt 		for (i = 3; i < argc; i++)
534cbf5262eSderaadt 			add_string(&p->objpaths, argv[i]);
535cbf5262eSderaadt 	} else {
536cbf5262eSderaadt 		fprintf(stderr, "%s:%d: bad parameter name `%s', skipping line.\n",
537cbf5262eSderaadt 		    curfilename, linenum, argv[2]);
538cbf5262eSderaadt 		goterror = 1;
539cbf5262eSderaadt 	}
540cbf5262eSderaadt 	return;
541cbf5262eSderaadt 
542cbf5262eSderaadt argcount:
543cbf5262eSderaadt 	fprintf(stderr,
544cbf5262eSderaadt 	    "%s:%d: too %s arguments, expected \"special %s %s <string>\".\n",
545cbf5262eSderaadt 	    curfilename, linenum, argc < 4 ? "few" : "many", argv[1], argv[2]);
546cbf5262eSderaadt 	goterror = 1;
547cbf5262eSderaadt }
548cbf5262eSderaadt 
549cbf5262eSderaadt prog_t  *
find_prog(char * str)550cbf5262eSderaadt find_prog(char *str)
551cbf5262eSderaadt {
552cbf5262eSderaadt 	prog_t         *p;
553cbf5262eSderaadt 
554cbf5262eSderaadt 	for (p = progs; p != NULL; p = p->next)
555cbf5262eSderaadt 		if (!strcmp(p->name, str))
556cbf5262eSderaadt 			return p;
557cbf5262eSderaadt 	return NULL;
558cbf5262eSderaadt }
559cbf5262eSderaadt 
560cbf5262eSderaadt void            remove_error_progs(void);
561cbf5262eSderaadt void            fillin_program(prog_t * p);
562cbf5262eSderaadt void            gen_specials_cache(void);
563cbf5262eSderaadt void            gen_output_makefile(void);
564cbf5262eSderaadt void            gen_output_cfile(void);
565cbf5262eSderaadt 
566cbf5262eSderaadt void            fillin_program_objs(prog_t * p, char *path);
567cbf5262eSderaadt void            top_makefile_rules(FILE * outmk);
568cbf5262eSderaadt void            prog_makefile_rules(FILE * outmk, prog_t * p);
569cbf5262eSderaadt void            output_strlst(FILE * outf, strlst_t * lst);
570cbf5262eSderaadt char           *genident(char *str);
571cbf5262eSderaadt char           *dir_search(char *progname);
572cbf5262eSderaadt 
573cbf5262eSderaadt void
gen_outputs(void)574cbf5262eSderaadt gen_outputs(void)
575cbf5262eSderaadt {
576cbf5262eSderaadt 	prog_t         *p;
577cbf5262eSderaadt 
578cbf5262eSderaadt 	for (p = progs; p != NULL; p = p->next)
579cbf5262eSderaadt 		fillin_program(p);
580cbf5262eSderaadt 
581cbf5262eSderaadt 	remove_error_progs();
582cbf5262eSderaadt 	gen_specials_cache();
583cbf5262eSderaadt 	gen_output_cfile();
584cbf5262eSderaadt 	gen_output_makefile();
585cbf5262eSderaadt }
586cbf5262eSderaadt 
587cbf5262eSderaadt void
fillin_program(prog_t * p)588cbf5262eSderaadt fillin_program(prog_t * p)
589cbf5262eSderaadt {
590b9fc9a72Sderaadt 	char            path[PATH_MAX];
591cbf5262eSderaadt 	char           *srcparent;
592cbf5262eSderaadt 	strlst_t       *s;
593cbf5262eSderaadt 	int             i;
594cbf5262eSderaadt 
595cbf5262eSderaadt 	if (!p->ident)
596cbf5262eSderaadt 		p->ident = genident(p->name);
597cbf5262eSderaadt 	if (!p->srcdir) {
598cbf5262eSderaadt 		srcparent = dir_search(p->name);
599cbf5262eSderaadt 		if (srcparent)
600cbf5262eSderaadt 			snprintf(path, sizeof(path), "%s/%s", srcparent, p->name);
601cbf5262eSderaadt 		if (is_dir(path))
602cbf5262eSderaadt 			p->srcdir = strdup(path);
603cbf5262eSderaadt 	}
604cbf5262eSderaadt 	if (!p->objdir && p->srcdir) {
605cbf5262eSderaadt 		snprintf(path, sizeof(path), "%s/%s", p->srcdir, objdir);
606cbf5262eSderaadt 		if (is_dir(path))
607cbf5262eSderaadt 			p->objdir = strdup(path);
608cbf5262eSderaadt 		else {
609cbf5262eSderaadt 			snprintf(path, sizeof(path), "%s/obj.%s", p->srcdir, MACHINE);
610cbf5262eSderaadt 			if (is_dir(path))
611cbf5262eSderaadt 				p->objdir = strdup(path);
612cbf5262eSderaadt 			else
613cbf5262eSderaadt 				p->objdir = p->srcdir;
614cbf5262eSderaadt 		}
6155dcb52a6Sfkr 		/* Fill p->mf_name so it is not a null pointer */
6165dcb52a6Sfkr 		for (i = 0; mf_name[i] != NULL; i++) {
6175dcb52a6Sfkr 			snprintf(path, sizeof(path), "%s/%s", p->srcdir, mf_name[i]);
6185dcb52a6Sfkr 			if (is_nonempty_file(path)) {
6195dcb52a6Sfkr 				p->mf_name = mf_name[i];
6205dcb52a6Sfkr 				break;
6215dcb52a6Sfkr 			}
6225dcb52a6Sfkr 		}
623cbf5262eSderaadt 	}
624cbf5262eSderaadt 	/* We have a sourcedir and no explicit objs, try */
625cbf5262eSderaadt 	/* to find makefile and get objs from it. */
626cbf5262eSderaadt 	if (p->srcdir && !p->objs) {
627cbf5262eSderaadt 		for (i = 0; mf_name[i] != NULL; i++) {
628cbf5262eSderaadt 			snprintf(path, sizeof(path), "%s/%s", p->srcdir, mf_name[i]);
629cbf5262eSderaadt 			if (is_nonempty_file(path)) {
630cbf5262eSderaadt 				p->mf_name = mf_name[i];
631cbf5262eSderaadt 				fillin_program_objs(p, path);
632cbf5262eSderaadt 				break;
633cbf5262eSderaadt 			}
634cbf5262eSderaadt 		}
635cbf5262eSderaadt 	}
636cbf5262eSderaadt 	if (!p->objpaths && p->objdir && p->objs)
637cbf5262eSderaadt 		for (s = p->objs; s != NULL; s = s->next) {
638cbf5262eSderaadt 			snprintf(line, sizeof(line), "%s/%s", p->objdir, s->str);
639cbf5262eSderaadt 			add_string(&p->objpaths, line);
640cbf5262eSderaadt 		}
641cbf5262eSderaadt 
642cbf5262eSderaadt 	if (!p->srcdir && verbose)
643cbf5262eSderaadt 		fprintf(stderr, "%s: %s: warning: could not find source directory.\n",
644cbf5262eSderaadt 		    infilename, p->name);
645cbf5262eSderaadt 	if (!p->objs && verbose)
646cbf5262eSderaadt 		fprintf(stderr, "%s: %s: warning: could not find any .o files.\n",
647cbf5262eSderaadt 		    infilename, p->name);
648cbf5262eSderaadt 
649cbf5262eSderaadt 	if (!p->objpaths) {
650cbf5262eSderaadt 		fprintf(stderr,
651cbf5262eSderaadt 		    "%s: %s: error: no objpaths specified or calculated.\n",
652cbf5262eSderaadt 		    infilename, p->name);
653cbf5262eSderaadt 		p->goterror = goterror = 1;
654cbf5262eSderaadt 	}
655cbf5262eSderaadt }
656cbf5262eSderaadt 
657cbf5262eSderaadt void
fillin_program_objs(prog_t * p,char * path)658cbf5262eSderaadt fillin_program_objs(prog_t * p, char *path)
659cbf5262eSderaadt {
66081b62b13Shenning 	char           *cp, *obj, tempfname[PATH_MAX], cwd[PATH_MAX];
66181b62b13Shenning 	int             fd, dotfd, rc;
662cbf5262eSderaadt 	FILE           *f;
663cbf5262eSderaadt 
664cbf5262eSderaadt 	/* discover the objs from the srcdir Makefile */
665cbf5262eSderaadt 
666cbf5262eSderaadt 	snprintf(tempfname, sizeof(tempfname), ".tmp_%sXXXXXXXXXX", confname);
667cbf5262eSderaadt 	if ((fd = mkstemp(tempfname)) == -1 || (f = fdopen(fd, "w")) == NULL) {
668cbf5262eSderaadt 		if (fd != -1)
669cbf5262eSderaadt 			close(fd);
670cbf5262eSderaadt 		perror(tempfname);
671cbf5262eSderaadt 		goterror = 1;
672cbf5262eSderaadt 		return;
673cbf5262eSderaadt 	}
674cbf5262eSderaadt 	fprintf(f, ".include \"%s\"\n", path);
675cbf5262eSderaadt 	fprintf(f, ".if defined(PROG) && !defined(OBJS)\n");
676cbf5262eSderaadt 	fprintf(f, "OBJS=${PROG}.o\n");
677cbf5262eSderaadt 	fprintf(f, ".endif\n");
678cbf5262eSderaadt 	fprintf(f, "crunchgen_objs:\n\t@echo 'OBJS= '${OBJS}\n");
679cbf5262eSderaadt 	fclose(f);
680cbf5262eSderaadt 
681b7041c07Sderaadt 	if ((dotfd = open(".", O_RDONLY)) == -1 ||
68281b62b13Shenning 	    getcwd(cwd, sizeof(cwd)) == NULL) {
68381b62b13Shenning 		perror("get cwd");
68481b62b13Shenning 		goterror = 1;
68581b62b13Shenning 		return;
68681b62b13Shenning 	}
68781b62b13Shenning 	if (chdir(dirname(path)) == -1) {
68881b62b13Shenning 		perror("chdir target dir");
68981b62b13Shenning 		goterror = 1;
69081b62b13Shenning 		return;
69181b62b13Shenning 	}
69281b62b13Shenning 	snprintf(line, sizeof(line), "make -f %s/%s crunchgen_objs 2>&1", cwd, tempfname);
693cbf5262eSderaadt 	if ((f = popen(line, "r")) == NULL) {
694cbf5262eSderaadt 		perror("submake pipe");
695cbf5262eSderaadt 		goterror = 1;
696cbf5262eSderaadt 		return;
697cbf5262eSderaadt 	}
69881b62b13Shenning 	if (fchdir(dotfd) == -1) {
69981b62b13Shenning 		perror("fchdir back");
70081b62b13Shenning 		goterror = 1;
70181b62b13Shenning 		return;
70281b62b13Shenning 	}
703cbf5262eSderaadt 	while (fgets(line, MAXLINELEN, f)) {
704cbf5262eSderaadt 		if (strncmp(line, "OBJS= ", 6)) {
705cbf5262eSderaadt 			if (strcmp(line,
706cbf5262eSderaadt 			    "sh: warning: running as root with dot in PATH\n") == 0)
707cbf5262eSderaadt 				continue;
708cbf5262eSderaadt 			fprintf(stderr, "make error: %s", line);
709cbf5262eSderaadt 			goterror = 1;
710cbf5262eSderaadt 			continue;
711cbf5262eSderaadt 		}
712cbf5262eSderaadt 		cp = line + 6;
713701d8205Sderaadt 		while (isspace((unsigned char)*cp))
714cbf5262eSderaadt 			cp++;
715cbf5262eSderaadt 		while (*cp) {
716cbf5262eSderaadt 			obj = cp;
717701d8205Sderaadt 			while (*cp && !isspace((unsigned char)*cp))
718cbf5262eSderaadt 				cp++;
719cbf5262eSderaadt 			if (*cp)
720cbf5262eSderaadt 				*cp++ = '\0';
721cbf5262eSderaadt 			add_string(&p->objs, obj);
722701d8205Sderaadt 			while (isspace((unsigned char)*cp))
723cbf5262eSderaadt 				cp++;
724cbf5262eSderaadt 		}
725cbf5262eSderaadt 	}
726cbf5262eSderaadt 	if ((rc = pclose(f)) != 0) {
727cbf5262eSderaadt 		fprintf(stderr, "make error: make returned %d\n", rc);
728cbf5262eSderaadt 		goterror = 1;
729cbf5262eSderaadt 	}
730cbf5262eSderaadt 	unlink(tempfname);
731cbf5262eSderaadt }
732cbf5262eSderaadt 
733cbf5262eSderaadt void
remove_error_progs(void)734cbf5262eSderaadt remove_error_progs(void)
735cbf5262eSderaadt {
736cbf5262eSderaadt 	prog_t         *p1, *p2;
737cbf5262eSderaadt 
738cbf5262eSderaadt 	p1 = NULL;
739cbf5262eSderaadt 	p2 = progs;
740cbf5262eSderaadt 	while (p2 != NULL) {
741cbf5262eSderaadt 		if (!p2->goterror)
742cbf5262eSderaadt 			p1 = p2, p2 = p2->next;
743cbf5262eSderaadt 		else {
744cbf5262eSderaadt 			/* delete it from linked list */
745cbf5262eSderaadt 			fprintf(stderr, "%s: %s: ignoring program because of errors.\n",
746cbf5262eSderaadt 			    infilename, p2->name);
747cbf5262eSderaadt 			if (p1)
748cbf5262eSderaadt 				p1->next = p2->next;
749cbf5262eSderaadt 			else
750cbf5262eSderaadt 				progs = p2->next;
751cbf5262eSderaadt 			p2 = p2->next;
752cbf5262eSderaadt 		}
753cbf5262eSderaadt 	}
754cbf5262eSderaadt }
755cbf5262eSderaadt 
756cbf5262eSderaadt void
gen_specials_cache(void)757cbf5262eSderaadt gen_specials_cache(void)
758cbf5262eSderaadt {
759cbf5262eSderaadt 	FILE           *cachef;
760cbf5262eSderaadt 	prog_t         *p;
761cbf5262eSderaadt 
762cbf5262eSderaadt 	if ((cachef = fopen(cachename, "w")) == NULL) {
763cbf5262eSderaadt 		perror(cachename);
764cbf5262eSderaadt 		goterror = 1;
765cbf5262eSderaadt 		return;
766cbf5262eSderaadt 	}
767cbf5262eSderaadt 	fprintf(cachef, "# %s - parm cache generated from %s by crunchgen %s\n\n",
768cbf5262eSderaadt 	    cachename, infilename, CRUNCH_VERSION);
769cbf5262eSderaadt 
770cbf5262eSderaadt 	for (p = progs; p != NULL; p = p->next) {
771cbf5262eSderaadt 		fprintf(cachef, "\n");
772cbf5262eSderaadt 		if (p->srcdir)
773cbf5262eSderaadt 			fprintf(cachef, "special %s srcdir %s\n", p->name, p->srcdir);
774cbf5262eSderaadt 		if (p->mf_name)
775cbf5262eSderaadt 			fprintf(cachef, "special %s mf_name %s\n", p->name, p->mf_name);
776cbf5262eSderaadt 		if (p->objdir)
777cbf5262eSderaadt 			fprintf(cachef, "special %s objdir %s\n", p->name, p->objdir);
778cbf5262eSderaadt 		if (p->objs) {
779cbf5262eSderaadt 			fprintf(cachef, "special %s objs", p->name);
780cbf5262eSderaadt 			output_strlst(cachef, p->objs);
781cbf5262eSderaadt 		}
782cbf5262eSderaadt 		fprintf(cachef, "special %s objpaths", p->name);
783cbf5262eSderaadt 		output_strlst(cachef, p->objpaths);
784cbf5262eSderaadt 	}
785cbf5262eSderaadt 	fclose(cachef);
786cbf5262eSderaadt }
787cbf5262eSderaadt 
788cbf5262eSderaadt void
gen_output_makefile(void)789cbf5262eSderaadt gen_output_makefile(void)
790cbf5262eSderaadt {
791cbf5262eSderaadt 	prog_t         *p;
792cbf5262eSderaadt 	FILE           *outmk;
793cbf5262eSderaadt 
794cbf5262eSderaadt 	if ((outmk = fopen(outmkname, "w")) == NULL) {
795cbf5262eSderaadt 		perror(outmkname);
796cbf5262eSderaadt 		goterror = 1;
797cbf5262eSderaadt 		return;
798cbf5262eSderaadt 	}
799cbf5262eSderaadt 	fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n",
800cbf5262eSderaadt 	    outmkname, infilename, CRUNCH_VERSION);
801cbf5262eSderaadt 
802cbf5262eSderaadt 	top_makefile_rules(outmk);
803cbf5262eSderaadt 
804cbf5262eSderaadt 	for (p = progs; p != NULL; p = p->next)
805cbf5262eSderaadt 		prog_makefile_rules(outmk, p);
806cbf5262eSderaadt 
807cbf5262eSderaadt 	fprintf(outmk, "\n# ========\n");
808cbf5262eSderaadt 	fclose(outmk);
809cbf5262eSderaadt }
810cbf5262eSderaadt 
811cbf5262eSderaadt void
gen_output_cfile(void)812cbf5262eSderaadt gen_output_cfile(void)
813cbf5262eSderaadt {
814cbf5262eSderaadt 	extern char    *crunched_skel[];
815cbf5262eSderaadt 	char          **cp;
816cbf5262eSderaadt 	FILE           *outcf;
817cbf5262eSderaadt 	prog_t         *p;
818cbf5262eSderaadt 	strlst_t       *s;
819cbf5262eSderaadt 
820cbf5262eSderaadt 	if ((outcf = fopen(outcfname, "w")) == NULL) {
821cbf5262eSderaadt 		perror(outcfname);
822cbf5262eSderaadt 		goterror = 1;
823cbf5262eSderaadt 		return;
824cbf5262eSderaadt 	}
825cbf5262eSderaadt 	fprintf(outcf, "/* %s - generated from %s by crunchgen %s */\n",
826cbf5262eSderaadt 	    outcfname, infilename, CRUNCH_VERSION);
827cbf5262eSderaadt 
828cbf5262eSderaadt 	fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname);
829cbf5262eSderaadt 	for (cp = crunched_skel; *cp != NULL; cp++)
830cbf5262eSderaadt 		fprintf(outcf, "%s\n", *cp);
831cbf5262eSderaadt 
832cbf5262eSderaadt 	for (p = progs; p != NULL; p = p->next)
833cbf5262eSderaadt 		fprintf(outcf, "extern int _crunched_%s_stub();\n", p->ident);
834cbf5262eSderaadt 
835cbf5262eSderaadt 	fprintf(outcf, "\nstruct stub entry_points[] = {\n");
836cbf5262eSderaadt 	for (p = progs; p != NULL; p = p->next) {
837cbf5262eSderaadt 		fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
838cbf5262eSderaadt 			p->name, p->ident);
839cbf5262eSderaadt 		for (s = p->links; s != NULL; s = s->next)
840cbf5262eSderaadt 			fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
841cbf5262eSderaadt 				s->str, p->ident);
842cbf5262eSderaadt 	}
843cbf5262eSderaadt 
844cbf5262eSderaadt 	fprintf(outcf, "\t{ EXECNAME, crunched_main },\n");
845cbf5262eSderaadt 	fprintf(outcf, "\t{ NULL, NULL }\n};\n");
846cbf5262eSderaadt 	fclose(outcf);
847cbf5262eSderaadt }
848cbf5262eSderaadt 
849cbf5262eSderaadt char           *
genident(char * str)850cbf5262eSderaadt genident(char *str)
851cbf5262eSderaadt {
852cbf5262eSderaadt 	char           *n, *s, *d;
853cbf5262eSderaadt 
854cbf5262eSderaadt 	/*
855cbf5262eSderaadt          * generates a Makefile/C identifier from a program name, mapping '-' to
856cbf5262eSderaadt          * '_' and ignoring all other non-identifier characters.  This leads to
857cbf5262eSderaadt          * programs named "foo.bar" and "foobar" to map to the same identifier.
858cbf5262eSderaadt          */
859cbf5262eSderaadt 
860cbf5262eSderaadt 	if ((n = strdup(str)) == NULL)
861cbf5262eSderaadt 		return NULL;
862cbf5262eSderaadt 	for (d = s = n; *s != '\0'; s++) {
863cbf5262eSderaadt 		if (*s == '-')
864cbf5262eSderaadt 			*d++ = '_';
865701d8205Sderaadt 		else if (*s == '_' || isalnum((unsigned char)*s))
866cbf5262eSderaadt 			*d++ = *s;
867cbf5262eSderaadt 	}
868cbf5262eSderaadt 	*d = '\0';
869cbf5262eSderaadt 	return n;
870cbf5262eSderaadt }
871cbf5262eSderaadt 
872cbf5262eSderaadt char           *
dir_search(char * progname)873cbf5262eSderaadt dir_search(char *progname)
874cbf5262eSderaadt {
875b9fc9a72Sderaadt 	char            path[PATH_MAX];
876cbf5262eSderaadt 	strlst_t       *dir;
877cbf5262eSderaadt 
878cbf5262eSderaadt 	for (dir = srcdirs; dir != NULL; dir = dir->next) {
879cbf5262eSderaadt 		snprintf(path, sizeof(path), "%s/%s", dir->str, progname);
880cbf5262eSderaadt 		if (is_dir(path))
881cbf5262eSderaadt 			return dir->str;
882cbf5262eSderaadt 	}
883cbf5262eSderaadt 	return NULL;
884cbf5262eSderaadt }
885cbf5262eSderaadt 
886cbf5262eSderaadt void
top_makefile_rules(FILE * outmk)887cbf5262eSderaadt top_makefile_rules(FILE * outmk)
888cbf5262eSderaadt {
889cbf5262eSderaadt 	prog_t         *p;
890cbf5262eSderaadt 	strlst_t       *l;
891cbf5262eSderaadt 
892cbf5262eSderaadt 
89352135926Spascal 	fprintf(outmk, ".include <bsd.own.mk>\n");
89452135926Spascal 	fprintf(outmk, "CFLAGS+=$(NOPIE_FLAGS)\n");
895a560fb78Sespie 	fprintf(outmk, "CFLAGS+=-Oz\n");
89624a45e1dSnaddy 	fprintf(outmk, "CFLAGS+=-fno-stack-protector\n");
89724a45e1dSnaddy 	fprintf(outmk, "CFLAGS+=-fno-unwind-tables\n");
898a7621e99Sderaadt 	fprintf(outmk, ".if ${MACHINE} == \"amd64\"\n");
899a7621e99Sderaadt 	fprintf(outmk, "CFLAGS+=-fcf-protection=none\n");
900*ea00e92bSderaadt 	fprintf(outmk, "CFLAGS+=-fno-ret-clean\n");
901a7621e99Sderaadt 	fprintf(outmk, ".endif\n");
902a7621e99Sderaadt 	fprintf(outmk, ".if ${MACHINE} == \"arm64\"\n");
903a7621e99Sderaadt 	fprintf(outmk, "CFLAGS+=-mbranch-protection=none\n");
904a7621e99Sderaadt 	fprintf(outmk, ".endif\n");
9058b790ea8Sjsg 	fprintf(outmk, "CFLAGS+=-fno-asynchronous-unwind-tables\n");
906586eb32bSderaadt 	fprintf(outmk, "LDFLAGS+=$(NOPIE_LDFLAGS)\n");
907cbf5262eSderaadt 	fprintf(outmk, "STRIP?=strip\n");
908e5d9e9b2Sjca 	fprintf(outmk, "LINK=$(LD) -d -r ${LDFLAGS}\n");
909cbf5262eSderaadt 	fprintf(outmk, "LIBS=");
910cbf5262eSderaadt 	for (l = libdirs; l != NULL; l = l->next)
911cbf5262eSderaadt 		fprintf(outmk, " -L%s", l->str);
912cbf5262eSderaadt 	output_strlst(outmk, libs);
913cbf5262eSderaadt 
914cbf5262eSderaadt 	fprintf(outmk, "CRUNCHED_OBJS=");
915cbf5262eSderaadt 	for (p = progs; p != NULL; p = p->next)
916cbf5262eSderaadt 		fprintf(outmk, " %s.lo", p->name);
917cbf5262eSderaadt 	fprintf(outmk, "\n");
918cbf5262eSderaadt 
919cbf5262eSderaadt 	fprintf(outmk, "SUBMAKE_TARGETS=");
920cbf5262eSderaadt 	for (p = progs; p != NULL; p = p->next)
921cbf5262eSderaadt 		fprintf(outmk, " %s_make", p->ident);
922cbf5262eSderaadt 	fprintf(outmk, "\n\n");
923cbf5262eSderaadt 
924ef0efd17Sguenther 	fprintf(outmk, "CLIB=\n");
925ef0efd17Sguenther 	fprintf(outmk, ".if defined(SRCLIBDIR)\n");
926ef0efd17Sguenther 	fprintf(outmk, ". for lib in ${LIBS:M-l*:S/-l//}\n");
927ef0efd17Sguenther 	fprintf(outmk, ".  if exists(${SRCLIBDIR}/lib${lib})\n");
928ef0efd17Sguenther 	fprintf(outmk, "CLIB+=lib${lib}.a\n");
929ef0efd17Sguenther 	fprintf(outmk, ".  endif\n");
930ef0efd17Sguenther 	fprintf(outmk, ". endfor\n");
931ef0efd17Sguenther 	fprintf(outmk, ".endif\n\n");
932ef0efd17Sguenther 
933ef0efd17Sguenther 	fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS) ${CLIB}\n",
934cbf5262eSderaadt 	    execfname, execfname);
935ef0efd17Sguenther 	fprintf(outmk, "\t$(CC) -static -L. ${LDFLAGS} -o $@ %s.o $(CRUNCHED_OBJS) $(LIBS)\n",
936cbf5262eSderaadt 	    execfname);
937b84aa302Ssemarie 	fprintf(outmk, "\t$(STRIP) -R .comment %s\n", execfname);
938ef0efd17Sguenther 
939ef0efd17Sguenther 	fprintf(outmk, "\n");
940ef0efd17Sguenther 	fprintf(outmk, ".if !empty(CLIB)\n");
941ef0efd17Sguenther 	fprintf(outmk, ".SUFFIXES: .a .olist\n");
942ef0efd17Sguenther 	fprintf(outmk, ".olist.a:\n");
943ef0efd17Sguenther 	fprintf(outmk, "\t@rm -f ${.TARGET}\n");
944ef0efd17Sguenther 	fprintf(outmk, "\t@cd ${SRCLIBDIR}/${.PREFIX} &&\t\t\t\t\\\n");
94524a45e1dSnaddy 	fprintf(outmk, "\t${MAKE} DIST_CFLAGS=\"${CFLAGS}\"\t\t\t\t\\\n");
94624a45e1dSnaddy 	fprintf(outmk, "\t    DIST_OBJS=\"`cat ${.OBJDIR}/${.IMPSRC}`\"\t\t\\\n");
947ef0efd17Sguenther 	fprintf(outmk, "\t    DIST_LIB=${.OBJDIR}/${.TARGET} ${.OBJDIR}/${.TARGET}\n\n");
948ef0efd17Sguenther 
949ef0efd17Sguenther 	fprintf(outmk, "%s.map: %s.o $(CRUNCHED_OBJS)\n", execfname, execfname);
9500ddee584Sguenther 	fprintf(outmk, "\t$(CC) -static ${LDFLAGS} -o %s.o.o %s.o $(CRUNCHED_OBJS) \\\n", execfname, execfname);
95138b4dc22Sguenther 	fprintf(outmk, "\t    $(LIBS) -Wl,--trace | sed -e 's/^(\\(..*\\))\\(..*\\)/\\1(\\2)/' >${.TARGET}\n\n");
952ef0efd17Sguenther 
953ef0efd17Sguenther 	fprintf(outmk, "${CLIB:.a=.olist}: %s.map\n", execfname);
95495887d58Sderaadt 	fprintf(outmk, "\tsed -n -e 's!^${DESTDIR}/usr/lib/${.TARGET:R}\\.a(\\([^)]*\\.o\\)).*!\\1!p' \\\n");
955ef0efd17Sguenther 	fprintf(outmk, "\t    < %s.map | tr '\\012' ' ' >$@\n", execfname);
956ef0efd17Sguenther 	fprintf(outmk, ".endif\n\n");
957ef0efd17Sguenther 
958cbf5262eSderaadt 	fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n");
959cbf5262eSderaadt 	fprintf(outmk, "exe: %s\n", execfname);
960cbf5262eSderaadt 	fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n",
961cbf5262eSderaadt 	    execfname);
962cbf5262eSderaadt 	fprintf(outmk, ".PHONY: all objs exe clean $(SUBMAKE_TARGETS)\n\n");
963cbf5262eSderaadt }
964cbf5262eSderaadt 
965cbf5262eSderaadt void
prog_makefile_rules(FILE * outmk,prog_t * p)966cbf5262eSderaadt prog_makefile_rules(FILE * outmk, prog_t * p)
967cbf5262eSderaadt {
968cbf5262eSderaadt 	fprintf(outmk, "\n# -------- %s\n\n", p->name);
969cbf5262eSderaadt 
970cbf5262eSderaadt 	if (p->srcdir && p->objs) {
971cbf5262eSderaadt 		fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir);
972cbf5262eSderaadt 		fprintf(outmk, "%s_OBJS=", p->ident);
973cbf5262eSderaadt 		output_strlst(outmk, p->objs);
974cbf5262eSderaadt 		fprintf(outmk, "%s_make:\n", p->ident);
975cbf5262eSderaadt 		fprintf(outmk, "\tcd $(%s_SRCDIR) && exec $(MAKE) -f %s $(%s_OBJS)\n\n",
976cbf5262eSderaadt 		    p->ident, p->mf_name, p->ident);
977cbf5262eSderaadt 	} else
978cbf5262eSderaadt 		fprintf(outmk, "%s_make:\n\t@echo \"** cannot make objs for %s\"\n\n",
979cbf5262eSderaadt 		    p->ident, p->name);
980cbf5262eSderaadt 
981cbf5262eSderaadt 	fprintf(outmk, "%s_OBJPATHS=", p->ident);
982cbf5262eSderaadt 	output_strlst(outmk, p->objpaths);
983cbf5262eSderaadt 
984cbf5262eSderaadt 	fprintf(outmk, "%s_stub.c:\n", p->name);
985a66c1913Sderaadt 	fprintf(outmk, "\t@echo \""
9863b318c57Sderaadt 	    "extern int main(int argc, char **argv, char **envp);\\\n"
987cbf5262eSderaadt 	    "int _crunched_%s_stub(int argc, char **argv, char **envp)"
988cbf5262eSderaadt 	    " { return main(argc, argv, envp); }\" >$@\n",
989cbf5262eSderaadt 	    p->ident);
990cbf5262eSderaadt 	fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)\n",
991cbf5262eSderaadt 	    p->name, p->name, p->ident);
992cbf5262eSderaadt 	fprintf(outmk, "\t$(LINK) -o $@ %s_stub.o $(%s_OBJPATHS)\n",
993cbf5262eSderaadt 	    p->name, p->ident);
994516251d4Sdrahn 	fprintf(outmk, "\tcrunchgen -h %s -k %s_crunched_%s_stub $@\n",
99503ab18c2Sdrahn 	    elf_mangle ? "-M" : "",
996cbf5262eSderaadt 	    elf_names ? "" : "_", p->ident);
997cbf5262eSderaadt }
998cbf5262eSderaadt 
999cbf5262eSderaadt void
output_strlst(FILE * outf,strlst_t * lst)1000cbf5262eSderaadt output_strlst(FILE * outf, strlst_t * lst)
1001cbf5262eSderaadt {
1002cbf5262eSderaadt 	for (; lst != NULL; lst = lst->next)
1003cbf5262eSderaadt 		fprintf(outf, " %s", lst->str);
1004cbf5262eSderaadt 	fprintf(outf, "\n");
1005cbf5262eSderaadt }
1006cbf5262eSderaadt 
1007cbf5262eSderaadt void
out_of_memory(void)1008cbf5262eSderaadt out_of_memory(void)
1009cbf5262eSderaadt {
1010cbf5262eSderaadt 	fprintf(stderr, "%s: %d: out of memory, stopping.\n", infilename, linenum);
1011cbf5262eSderaadt 	exit(1);
1012cbf5262eSderaadt }
1013cbf5262eSderaadt 
1014cbf5262eSderaadt void
add_string(strlst_t ** listp,char * str)1015cbf5262eSderaadt add_string(strlst_t ** listp, char *str)
1016cbf5262eSderaadt {
1017cbf5262eSderaadt 	strlst_t       *p1, *p2;
1018cbf5262eSderaadt 
1019cbf5262eSderaadt 	/* add to end, but be smart about dups */
1020cbf5262eSderaadt 
1021cbf5262eSderaadt 	for (p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next)
1022cbf5262eSderaadt 		if (!strcmp(p2->str, str))
1023cbf5262eSderaadt 			return;
1024cbf5262eSderaadt 
1025cbf5262eSderaadt 	p2 = calloc(1, sizeof(strlst_t));
1026cbf5262eSderaadt 	if (p2)
1027cbf5262eSderaadt 		p2->str = strdup(str);
1028cbf5262eSderaadt 	if (!p2 || !p2->str)
1029cbf5262eSderaadt 		out_of_memory();
1030cbf5262eSderaadt 
1031cbf5262eSderaadt 	p2->next = NULL;
1032cbf5262eSderaadt 	if (p1 == NULL)
1033cbf5262eSderaadt 		*listp = p2;
1034cbf5262eSderaadt 	else
1035cbf5262eSderaadt 		p1->next = p2;
1036cbf5262eSderaadt }
1037cbf5262eSderaadt 
1038cbf5262eSderaadt int
is_dir(char * pathname)1039cbf5262eSderaadt is_dir(char *pathname)
1040cbf5262eSderaadt {
1041cbf5262eSderaadt 	struct stat     buf;
1042cbf5262eSderaadt 
1043cbf5262eSderaadt 	if (stat(pathname, &buf) == -1)
1044cbf5262eSderaadt 		return 0;
1045cbf5262eSderaadt 	return S_ISDIR(buf.st_mode);
1046cbf5262eSderaadt }
1047cbf5262eSderaadt 
1048cbf5262eSderaadt int
is_nonempty_file(char * pathname)1049cbf5262eSderaadt is_nonempty_file(char *pathname)
1050cbf5262eSderaadt {
1051cbf5262eSderaadt 	struct stat     buf;
1052cbf5262eSderaadt 
1053cbf5262eSderaadt 	if (stat(pathname, &buf) == -1)
1054cbf5262eSderaadt 		return 0;
1055cbf5262eSderaadt 
1056cbf5262eSderaadt 	return S_ISREG(buf.st_mode) && buf.st_size > 0;
1057cbf5262eSderaadt }
1058