xref: /dragonfly/usr.sbin/config/main.c (revision 23265324)
1 /*
2  * Copyright (c) 1980, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#) Copyright (c) 1980, 1993 The Regents of the University of California.  All rights reserved.
34  * @(#)main.c	8.1 (Berkeley) 6/6/93
35  * $FreeBSD: src/usr.sbin/config/main.c,v 1.37.2.3 2001/06/13 00:25:53 cg Exp $
36  * $DragonFly: src/usr.sbin/config/main.c,v 1.21 2007/01/19 07:23:43 dillon Exp $
37  */
38 
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/file.h>
42 #include <sys/mman.h>
43 #include <sys/param.h>
44 #include <ctype.h>
45 #include <err.h>
46 #include <stdio.h>
47 #include <dirent.h>
48 #include <sysexits.h>
49 #include <unistd.h>
50 #include "y.tab.h"
51 #include "config.h"
52 
53 #ifndef TRUE
54 #define TRUE	(1)
55 #endif
56 
57 #ifndef FALSE
58 #define FALSE	(0)
59 #endif
60 
61 #define	CDIR	"../compile/"
62 
63 char *	PREFIX;
64 char 	destdir[MAXPATHLEN];
65 char 	srcdir[MAXPATHLEN];
66 
67 static int no_config_clobber = TRUE;
68 int	debugging;
69 int	profiling;
70 
71 static void configfile(void);
72 static void get_srcdir(void);
73 static void usage(void);
74 
75 /*
76  * Config builds a set of files for building a UNIX
77  * system given a description of the desired system.
78  */
79 int
80 main(int argc, char *argv[])
81 {
82 	struct stat buf;
83 	int ch, len;
84 	unsigned int i;
85 	char *p;
86 	char linksrc[64], linkdest[MAXPATHLEN];
87 	static const char *emus[] = { "linux" };
88 
89 	while ((ch = getopt(argc, argv, "d:gprn")) != -1)
90 		switch (ch) {
91 		case 'd':
92 			if (*destdir == '\0')
93 				strlcpy(destdir, optarg, sizeof(destdir));
94 			else
95 				errx(2, "directory already set");
96 			break;
97 		case 'g':
98 			debugging++;
99 			break;
100 		case 'p':
101 			profiling++;
102 			break;
103 		case 'n':
104 			/* no_config_clobber is now true by default, no-op */
105 			fprintf(stderr,
106 				"*** Using obsolete config option '-n' ***\n");
107 			break;
108 		case 'r':
109 			no_config_clobber = FALSE;
110 			break;
111 		case '?':
112 		default:
113 			usage();
114 		}
115 	argc -= optind;
116 	argv += optind;
117 
118 	if (argc != 1)
119 		usage();
120 
121 	if (freopen(PREFIX = *argv, "r", stdin) == NULL)
122 		err(2, "%s", PREFIX);
123 
124 	if (*destdir != '\0') {
125 		len = strlen(destdir);
126 		while (len > 1 && destdir[len - 1] == '/')
127 			destdir[--len] = '\0';
128 		get_srcdir();
129 	} else {
130 		strlcpy(destdir, CDIR, sizeof(destdir));
131 		strlcat(destdir, PREFIX, sizeof(destdir));
132 	}
133 
134 	p = path((char *)NULL);
135 	if (stat(p, &buf)) {
136 		if (mkdir(p, 0777))
137 			err(2, "%s", p);
138 	}
139 	else if ((buf.st_mode & S_IFMT) != S_IFDIR) {
140 		errx(2, "%s isn't a directory", p);
141 	}
142 	else if (!no_config_clobber) {
143 		char tmp[strlen(p) + 8];
144 
145 		fprintf(stderr, "Removing old directory %s:  ", p);
146 		fflush(stderr);
147 		snprintf(tmp, sizeof(tmp), "rm -rf %s", p);
148 		if (system(tmp)) {
149 			fprintf(stderr, "Failed!\n");
150 			err(2, "%s", tmp);
151 		}
152 		fprintf(stderr, "Done.\n");
153 		if (mkdir(p, 0777))
154 			err(2, "%s", p);
155 	}
156 
157 	dtab = NULL;
158 	if (yyparse())
159 		exit(3);
160 	if (platformname == NULL) {
161 		printf("Specify platform architecture, e.g. 'platform pc32'\n");
162 		exit(1);
163 	}
164 	if (machinename == NULL) {
165 		printf("Specify machine architecture, e.g. 'machine i386'\n");
166 		exit(1);
167 	}
168 	if (machinearchname == NULL) {
169 		printf("Specify cpu architecture, e.g. 'machine_arch i386'\n");
170 		exit(1);
171 	}
172 	newbus_ioconf();
173 
174 	/*
175 	 * "machine" points into platform/<PLATFORM>/include
176 	 */
177 	if (*srcdir == '\0')
178 		snprintf(linkdest, sizeof(linkdest), "../../platform/%s/include",
179 		    platformname);
180 	else
181 		snprintf(linkdest, sizeof(linkdest), "%s/platform/%s/include",
182 		    srcdir, platformname);
183 	symlink(linkdest, path("machine"));
184 
185 	/*
186 	 * "machine_base" points into platform/<PLATFORM>
187 	 */
188 	if (*srcdir == '\0')
189 		snprintf(linkdest, sizeof(linkdest), "../../platform/%s",
190 		    platformname);
191 	else
192 		snprintf(linkdest, sizeof(linkdest), "%s/platform/%s",
193 		    srcdir, platformname);
194 	symlink(linkdest, path("machine_base"));
195 
196 	/*
197 	 * "cpu" points to cpu/<MACHINE_ARCH>/include
198 	 */
199 	if (*srcdir == '\0')
200 		snprintf(linkdest, sizeof(linkdest),
201 			 "../../cpu/%s/include", machinearchname);
202 	else
203 		snprintf(linkdest, sizeof(linkdest),
204 			 "%s/cpu/%s/include", srcdir, machinearchname);
205 	symlink(linkdest, path("cpu"));
206 
207 	/*
208 	 * "cpu_base" points to cpu/<MACHINE_ARCH>
209 	 */
210 	if (*srcdir == '\0')
211 		snprintf(linkdest, sizeof(linkdest), "../../cpu/%s",
212 		    machinearchname);
213 	else
214 		snprintf(linkdest, sizeof(linkdest), "%s/cpu/%s",
215 		    srcdir, machinearchname);
216 	symlink(linkdest, path("cpu_base"));
217 
218 	/*
219 	 * XXX check directory structure for architecture subdirectories and
220 	 * create the symlinks automatically XXX
221 	 */
222 	if (*srcdir == '\0')
223 		snprintf(linkdest, sizeof(linkdest),
224 		    "../../../../../net/i4b/include/%s",
225 		    machinearchname);
226 	else
227 		snprintf(linkdest, sizeof(linkdest), "%s/net/i4b/include/%s",
228 		    srcdir, machinearchname);
229 	mkdir(path("net"), 0755);
230 	mkdir(path("net/i4b"), 0755);
231 	mkdir(path("net/i4b/include"), 0755);
232 	symlink(linkdest, path("net/i4b/include/machine"));
233 
234 	for (i = 0; i < sizeof(emus) / sizeof(emus[0]); ++i) {
235 		if (*srcdir == 0)  {
236 			snprintf(linkdest, sizeof(linkdest),
237 			    "../../emulation/%s/%s",
238 			    emus[i], machinearchname);
239 		} else {
240 			snprintf(linkdest, sizeof(linkdest),
241 			    "%s/emulation/%s/%s",
242 			    srcdir, emus[i], machinearchname);
243 		}
244 		snprintf(linksrc, sizeof(linksrc), "arch_%s", emus[i]);
245 		symlink(linkdest, path(linksrc));
246 	}
247 
248 	options();			/* make options .h files */
249 	makefile();			/* build Makefile */
250 	headers();			/* make a lot of .h files */
251 	configfile();			/* put config file into kernel*/
252 	printf("Kernel build directory is %s\n", p);
253 	exit(EX_OK);
254 }
255 
256 /*
257  * get_srcdir
258  *	determine the root of the kernel source tree
259  *	and save that in srcdir.
260  */
261 static void
262 get_srcdir(void)
263 {
264 
265 	if (realpath("..", srcdir) == NULL)
266 		errx(2, "Unable to find root of source tree");
267 }
268 
269 static void
270 usage(void)
271 {
272 
273 	fprintf(stderr, "usage: config [-gpr] [-d destdir] sysname\n");
274 	exit(1);
275 }
276 
277 /*
278  * get_word
279  *	returns EOF on end of file
280  *	NULL on end of line
281  *	pointer to the word otherwise
282  */
283 char *
284 get_word(FILE *fp)
285 {
286 	static char line[80];
287 	int ch;
288 	char *cp;
289 	int escaped_nl = 0;
290 
291 begin:
292 	while ((ch = getc(fp)) != EOF)
293 		if (ch != ' ' && ch != '\t')
294 			break;
295 	if (ch == EOF)
296 		return((char *)EOF);
297 	if (ch == '\\') {
298 		escaped_nl = 1;
299 		goto begin;
300 	}
301 	if (ch == '\n') {
302 		if (escaped_nl) {
303 			escaped_nl = 0;
304 			goto begin;
305 		}
306 		else
307 			return(NULL);
308 	}
309 	cp = line;
310 	*cp++ = ch;
311 	while ((ch = getc(fp)) != EOF) {
312 		if (isspace(ch))
313 			break;
314 		*cp++ = ch;
315 	}
316 	*cp = 0;
317 	if (ch == EOF)
318 		return((char *)EOF);
319 	ungetc(ch, fp);
320 	return(line);
321 }
322 
323 /*
324  * get_quoted_word
325  *	like get_word but will accept something in double or single quotes
326  *	(to allow embedded spaces).
327  */
328 char *
329 get_quoted_word(FILE *fp)
330 {
331 	static char line[256];
332 	int ch;
333 	char *cp;
334 	int escaped_nl = 0;
335 
336 begin:
337 	while ((ch = getc(fp)) != EOF)
338 		if (ch != ' ' && ch != '\t')
339 			break;
340 	if (ch == EOF)
341 		return((char *)EOF);
342 	if (ch == '\\') {
343 		escaped_nl = 1;
344 		goto begin;
345 	}
346 	if (ch == '\n') {
347 		if (escaped_nl) {
348 			escaped_nl = 0;
349 			goto begin;
350 		}
351 		else
352 			return(NULL);
353 	}
354 	cp = line;
355 	if (ch == '"' || ch == '\'') {
356 		int quote = ch;
357 
358 		while ((ch = getc(fp)) != EOF) {
359 			if (ch == quote)
360 				break;
361 			if (ch == '\n') {
362 				*cp = 0;
363 				printf("config: missing quote reading `%s'\n",
364 					line);
365 				exit(2);
366 			}
367 			*cp++ = ch;
368 		}
369 	} else {
370 		*cp++ = ch;
371 		while ((ch = getc(fp)) != EOF) {
372 			if (isspace(ch))
373 				break;
374 			*cp++ = ch;
375 		}
376 		if (ch != EOF)
377 			ungetc(ch, fp);
378 	}
379 	*cp = 0;
380 	if (ch == EOF)
381 		return((char *)EOF);
382 	return(line);
383 }
384 
385 /*
386  * prepend the path to a filename
387  */
388 char *
389 path(const char *file)
390 {
391 	char *cp;
392 
393 	cp = malloc((size_t)(strlen(destdir) + (file ? strlen(file) : 0) + 2));
394 	strcpy(cp, destdir);
395 	if (file != NULL) {
396 		strcat(cp, "/");
397 		strcat(cp, file);
398 	}
399 	return(cp);
400 }
401 
402 static void
403 configfile(void)
404 {
405 	FILE *fi, *fo;
406 	char *p;
407 	int i;
408 
409 	fi = fopen(PREFIX, "r");
410 	if (fi == NULL)
411 		err(2, "%s", PREFIX);
412 	fo = fopen(p = path("config.c.new"), "w");
413 	if (fo == NULL)
414 		err(2, "%s", p);
415 	fprintf(fo, "#include \"opt_config.h\"\n");
416 	fprintf(fo, "#ifdef INCLUDE_CONFIG_FILE \n");
417 	fprintf(fo, "static const char config[] = \"\\\n");
418 	fprintf(fo, "START CONFIG FILE %s\\n\\\n___", PREFIX);
419 	while (EOF != (i = getc(fi))) {
420 		if (i == '\n') {
421 			fprintf(fo, "\\n\\\n___");
422 		} else if (i == '\"') {
423 			fprintf(fo, "\\\"");
424 		} else if (i == '\\') {
425 			fprintf(fo, "\\\\");
426 		} else {
427 			putc(i, fo);
428 		}
429 	}
430 	fprintf(fo, "\\n\\\nEND CONFIG FILE %s\\n\\\n", PREFIX);
431 	fprintf(fo, "\";\n");
432 	fprintf(fo, "\n#endif /* INCLUDE_CONFIG_FILE */\n");
433 	fclose(fi);
434 	fclose(fo);
435 	moveifchanged(path("config.c.new"), path("config.c"));
436 }
437 
438 /*
439  * moveifchanged --
440  *	compare two files; rename if changed.
441  */
442 void
443 moveifchanged(const char *from_name, const char *to_name)
444 {
445 	char *p, *q;
446 	int changed;
447 	size_t tsize;
448 	struct stat from_sb, to_sb;
449 	int from_fd, to_fd;
450 
451 	changed = 0;
452 
453 	if ((from_fd = open(from_name, O_RDONLY)) < 0)
454 		err(EX_OSERR, "moveifchanged open(%s)", from_name);
455 
456 	if ((to_fd = open(to_name, O_RDONLY)) < 0)
457 		changed++;
458 
459 	if (!changed && fstat(from_fd, &from_sb) < 0)
460 		err(EX_OSERR, "moveifchanged fstat(%s)", from_name);
461 
462 	if (!changed && fstat(to_fd, &to_sb) < 0)
463 		err(EX_OSERR, "moveifchanged fstat(%s)", to_name);
464 
465 	if (!changed && from_sb.st_size != to_sb.st_size)
466 		changed++;
467 
468 	tsize = (size_t)from_sb.st_size;
469 
470 	if (!changed) {
471 		p = mmap(NULL, tsize, PROT_READ, MAP_SHARED, from_fd, (off_t)0);
472 #ifndef MAP_FAILED
473 #define MAP_FAILED ((caddr_t)-1)
474 #endif
475 		if (p == MAP_FAILED)
476 			err(EX_OSERR, "mmap %s", from_name);
477 		q = mmap(NULL, tsize, PROT_READ, MAP_SHARED, to_fd, (off_t)0);
478 		if (q == MAP_FAILED)
479 			err(EX_OSERR, "mmap %s", to_name);
480 
481 		changed = memcmp(p, q, tsize);
482 		munmap(p, tsize);
483 		munmap(q, tsize);
484 	}
485 	if (changed) {
486 		if (rename(from_name, to_name) < 0)
487 			err(EX_OSERR, "rename(%s, %s)", from_name, to_name);
488 	} else {
489 		if (unlink(from_name) < 0)
490 			err(EX_OSERR, "unlink(%s)", from_name);
491 	}
492 }
493